vserver 1.9.5.x5
[linux-2.6.git] / drivers / media / video / cx88 / cx88-tvaudio.c
index f6def3d..874d297 100644 (file)
@@ -1,4 +1,6 @@
 /*
+    $Id: cx88-tvaudio.c,v 1.24 2004/10/25 11:51:00 kraxel Exp $
+
     cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver
 
      (c) 2001 Michael Eskin, Tom Zakrajsek [Windows version]
@@ -16,9 +18,9 @@
 
     Some comes from the dscaler sources, one of the dscaler driver guy works
     for Conexant ...
-    
+
     -----------------------------------------------------------------------
-    
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
 
 #include "cx88.h"
 
 static unsigned int audio_debug = 1;
-MODULE_PARM(audio_debug,"i");
+module_param(audio_debug,int,0644);
 MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]");
 
 #define dprintk(fmt, arg...)   if (audio_debug) \
-       printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
+       printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
 
 /* ----------------------------------------------------------- */
 
@@ -93,7 +97,7 @@ struct rlist {
        u32 val;
 };
 
-static void set_audio_registers(struct cx8800_dev *dev,
+static void set_audio_registers(struct cx88_core *core,
                                const struct rlist *l)
 {
        int i;
@@ -115,7 +119,7 @@ static void set_audio_registers(struct cx8800_dev *dev,
        }
 }
 
-static void set_audio_start(struct cx8800_dev *dev,
+static void set_audio_start(struct cx88_core *core,
                            u32 mode, u32 ctl)
 {
        // mute
@@ -133,7 +137,7 @@ static void set_audio_start(struct cx8800_dev *dev,
        cx_write(AUD_CTL,           ctl);
 }
 
-static void set_audio_finish(struct cx8800_dev *dev)
+static void set_audio_finish(struct cx88_core *core)
 {
        u32 volume;
 
@@ -150,7 +154,7 @@ static void set_audio_finish(struct cx8800_dev *dev)
 
 /* ----------------------------------------------------------- */
 
-static void set_audio_standard_BTSC(struct cx8800_dev *dev, unsigned int sap)
+static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap)
 {
        static const struct rlist btsc[] = {
                /* from dscaler */
@@ -247,19 +251,19 @@ static void set_audio_standard_BTSC(struct cx8800_dev *dev, unsigned int sap)
        // dscaler: don't know why to set EN_FMRADIO_EN_RDS
        if (sap) {
                dprintk("%s SAP (status: unknown)\n",__FUNCTION__);
-               set_audio_start(dev, 0x0001,
+               set_audio_start(core, 0x0001,
                                EN_FMRADIO_EN_RDS | EN_BTSC_FORCE_SAP);
-               set_audio_registers(dev, btsc_sap);
+               set_audio_registers(core, btsc_sap);
        } else {
                dprintk("%s (status: known-good)\n",__FUNCTION__);
-               set_audio_start(dev, 0x0001,
+               set_audio_start(core, 0x0001,
                                EN_FMRADIO_EN_RDS | EN_BTSC_AUTO_STEREO);
-               set_audio_registers(dev, btsc);
+               set_audio_registers(core, btsc);
        }
-       set_audio_finish(dev);
+       set_audio_finish(core);
 }
 
-static void set_audio_standard_NICAM(struct cx8800_dev *dev)
+static void set_audio_standard_NICAM(struct cx88_core *core)
 {
        static const struct rlist nicam_common[] = {
                /* from dscaler */
@@ -316,24 +320,25 @@ static void set_audio_standard_NICAM(struct cx8800_dev *dev)
                 { /* end of list */ },
        };
 
-        set_audio_start(dev, 0x0010,
+        set_audio_start(core, 0x0010,
                        EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
-        set_audio_registers(dev, nicam_common);
-       switch (dev->tvaudio) {
+        set_audio_registers(core, nicam_common);
+       switch (core->tvaudio) {
        case WW_NICAM_I:
                dprintk("%s PAL-I NICAM (status: unknown)\n",__FUNCTION__);
-               set_audio_registers(dev, nicam_pal_i);
+               set_audio_registers(core, nicam_pal_i);
+               break;
        case WW_NICAM_BGDKL:
-               dprintk("%s PAL NICAM (status: unknown)\n",__FUNCTION__);
-               set_audio_registers(dev, nicam_default);
+               dprintk("%s PAL-BGDK NICAM (status: unknown)\n",__FUNCTION__);
+               set_audio_registers(core, nicam_default);
                break;
        };
-        set_audio_finish(dev);
+        set_audio_finish(core);
 }
 
-static void set_audio_standard_NICAM_L(struct cx8800_dev *dev)
+static void set_audio_standard_NICAM_L(struct cx88_core *core)
 {
-       /* This is officially wierd.. register dumps indicate windows
+       /* This is officially weird.. register dumps indicate windows
         * uses audio mode 4.. A2. Let's operate and find out. */
 
        static const struct rlist nicam_l[] = {
@@ -449,13 +454,13 @@ static void set_audio_standard_NICAM_L(struct cx8800_dev *dev)
        };
 
        dprintk("%s (status: unknown)\n",__FUNCTION__);
-        set_audio_start(dev, 0x0004,
+        set_audio_start(core, 0x0004,
                        0 /* FIXME */);
-       set_audio_registers(dev, nicam_l);
-        set_audio_finish(dev);
+       set_audio_registers(core, nicam_l);
+        set_audio_finish(core);
 }
 
-static void set_audio_standard_A2(struct cx8800_dev *dev)
+static void set_audio_standard_A2(struct cx88_core *core)
 {
        /* from dscaler cvs */
        static const struct rlist a2_common[] = {
@@ -545,26 +550,33 @@ static void set_audio_standard_A2(struct cx8800_dev *dev)
                { /* end of list */ },
        };
 
-       set_audio_start(dev, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO);
-       set_audio_registers(dev, a2_common);
-       switch (dev->tvaudio) {
+       set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO);
+       set_audio_registers(core, a2_common);
+       switch (core->tvaudio) {
+       case WW_NICAM_I:
+               /* gives at least mono according to the dscaler guys */
+               /* so use use that while nicam is broken ...         */
+               dprintk("%s PAL-I mono (status: unknown)\n",__FUNCTION__);
+               set_audio_registers(core, a2_table1);
+               cx_write(AUD_CTL, EN_A2_FORCE_MONO1);
+               break;
        case WW_A2_BG:
                dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
-               set_audio_registers(dev, a2_table1);
+               set_audio_registers(core, a2_table1);
                break;
        case WW_A2_DK:
                dprintk("%s PAL-DK A2 (status: known-good)\n",__FUNCTION__);
-               set_audio_registers(dev, a2_table2);
+               set_audio_registers(core, a2_table2);
                break;
        case WW_A2_M:
                dprintk("%s NTSC-M A2 (status: unknown)\n",__FUNCTION__);
-               set_audio_registers(dev, a2_table3);
+               set_audio_registers(core, a2_table3);
                break;
        };
-       set_audio_finish(dev);
+       set_audio_finish(core);
 }
 
-static void set_audio_standard_EIAJ(struct cx8800_dev *dev)
+static void set_audio_standard_EIAJ(struct cx88_core *core)
 {
        static const struct rlist eiaj[] = {
                /* TODO: eiaj register settings are not there yet ... */
@@ -573,12 +585,12 @@ static void set_audio_standard_EIAJ(struct cx8800_dev *dev)
        };
        dprintk("%s (status: unknown)\n",__FUNCTION__);
 
-       set_audio_start(dev, 0x0002, EN_EIAJ_AUTO_STEREO);
-       set_audio_registers(dev, eiaj);
-       set_audio_finish(dev);
+       set_audio_start(core, 0x0002, EN_EIAJ_AUTO_STEREO);
+       set_audio_registers(core, eiaj);
+       set_audio_finish(core);
 }
 
-static void set_audio_standard_FM(struct cx8800_dev *dev)
+static void set_audio_standard_FM(struct cx88_core *core)
 {
 #if 0 /* FIXME */
        switch (dev->audio_properties.FM_deemphasis)
@@ -596,7 +608,7 @@ static void set_audio_standard_FM(struct cx8800_dev *dev)
                        cx_write(AUD_DEEMPH1_B0, 0x1C29);
                        cx_write(AUD_DEEMPH1_A1, 0x3FC66);
                        cx_write(AUD_DEEMPH1_B1, 0x399A);
-                       
+
                        break;
 
                case WW_FM_DEEMPH_75:
@@ -618,50 +630,51 @@ static void set_audio_standard_FM(struct cx8800_dev *dev)
 #endif
 
        dprintk("%s (status: unknown)\n",__FUNCTION__);
-       set_audio_start(dev, 0x0020, EN_FMRADIO_AUTO_STEREO);
+       set_audio_start(core, 0x0020, EN_FMRADIO_AUTO_STEREO);
 
        // AB: 10/2/01: this register is not being reset appropriately on occasion.
        cx_write(AUD_POLYPH80SCALEFAC,3);
 
-       set_audio_finish(dev);
+       set_audio_finish(core);
 }
 
 /* ----------------------------------------------------------- */
 
-void cx88_set_tvaudio(struct cx8800_dev *dev)
+void cx88_set_tvaudio(struct cx88_core *core)
 {
-       switch (dev->tvaudio) {
+       switch (core->tvaudio) {
        case WW_BTSC:
-               set_audio_standard_BTSC(dev,0);
+               set_audio_standard_BTSC(core,0);
                break;
-       case WW_NICAM_I:
+       // case WW_NICAM_I:
        case WW_NICAM_BGDKL:
-               set_audio_standard_NICAM(dev);
+               set_audio_standard_NICAM(core);
                break;
+       case WW_NICAM_I:
        case WW_A2_BG:
        case WW_A2_DK:
        case WW_A2_M:
-               set_audio_standard_A2(dev);
+               set_audio_standard_A2(core);
                break;
        case WW_EIAJ:
-               set_audio_standard_EIAJ(dev);
+               set_audio_standard_EIAJ(core);
                break;
        case WW_FM:
-               set_audio_standard_FM(dev);
+               set_audio_standard_FM(core);
                break;
        case WW_SYSTEM_L_AM:
-               set_audio_standard_NICAM_L(dev);
+               set_audio_standard_NICAM_L(core);
                break;
        case WW_NONE:
        default:
-               printk("%s: unknown tv audio mode [%d]\n",
-                      dev->name, dev->tvaudio);
+               printk("%s/0: unknown tv audio mode [%d]\n",
+                      core->name, core->tvaudio);
                break;
        }
        return;
 }
 
-void cx88_get_stereo(struct cx8800_dev *dev, struct v4l2_tuner *t)
+void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
 {
        static char *m[] = {"stereo", "dual mono", "mono", "sap"};
        static char *p[] = {"no pilot", "pilot c1", "pilot c2", "?"};
@@ -670,16 +683,28 @@ void cx88_get_stereo(struct cx8800_dev *dev, struct v4l2_tuner *t)
        reg   = cx_read(AUD_STATUS);
        mode  = reg & 0x03;
        pilot = (reg >> 2) & 0x03;
-       dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n",
-               reg, m[mode], p[pilot],
-               aud_ctl_names[cx_read(AUD_CTL) & 63]);
+
+       if (core->astat != reg)
+               dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n",
+                       reg, m[mode], p[pilot],
+                       aud_ctl_names[cx_read(AUD_CTL) & 63]);
+       core->astat = reg;
 
        t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
                V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
        t->rxsubchans = V4L2_TUNER_SUB_MONO;
        t->audmode    = V4L2_TUNER_MODE_MONO;
 
-       switch (dev->tvaudio) {
+       switch (core->tvaudio) {
+       case WW_BTSC:
+               t->capability = V4L2_TUNER_CAP_STEREO |
+                       V4L2_TUNER_CAP_SAP;
+               t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+               if (1 == pilot) {
+                       /* SAP */
+                       t->rxsubchans |= V4L2_TUNER_SUB_SAP;
+               }
+               break;
        case WW_A2_BG:
        case WW_A2_DK:
        case WW_A2_M:
@@ -707,17 +732,33 @@ void cx88_get_stereo(struct cx8800_dev *dev, struct v4l2_tuner *t)
        return;
 }
 
-void cx88_set_stereo(struct cx8800_dev *dev, u32 mode)
+void cx88_set_stereo(struct cx88_core *core, u32 mode)
 {
        u32 ctl  = UNSET;
        u32 mask = UNSET;
 
-       switch (dev->tvaudio) {
+       switch (core->tvaudio) {
+       case WW_BTSC:
+               switch (mode) {
+               case V4L2_TUNER_MODE_MONO:
+                       ctl  = EN_BTSC_FORCE_MONO;
+                       mask = 0x3f;
+                       break;
+               case V4L2_TUNER_MODE_SAP:
+                       ctl  = EN_BTSC_FORCE_SAP;
+                       mask = 0x3f;
+                       break;
+               case V4L2_TUNER_MODE_STEREO:
+                       ctl  = EN_BTSC_AUTO_STEREO;
+                       mask = 0x3f;
+                       break;
+               }
+               break;
        case WW_A2_BG:
        case WW_A2_DK:
        case WW_A2_M:
                switch (mode) {
-               case V4L2_TUNER_MODE_MONO:   
+               case V4L2_TUNER_MODE_MONO:
                case V4L2_TUNER_MODE_LANG1:
                        ctl  = EN_A2_FORCE_MONO1;
                        mask = 0x3f;
@@ -734,7 +775,7 @@ void cx88_set_stereo(struct cx8800_dev *dev, u32 mode)
                break;
        case WW_NICAM_BGDKL:
                switch (mode) {
-               case V4L2_TUNER_MODE_MONO:   
+               case V4L2_TUNER_MODE_MONO:
                        ctl  = EN_NICAM_FORCE_MONO1;
                        mask = 0x3f;
                        break;
@@ -747,10 +788,10 @@ void cx88_set_stereo(struct cx8800_dev *dev, u32 mode)
                        mask = 0x93f;
                        break;
                }
-               break;  
+               break;
        case WW_FM:
                switch (mode) {
-               case V4L2_TUNER_MODE_MONO:   
+               case V4L2_TUNER_MODE_MONO:
                        ctl  = EN_FMRADIO_FORCE_MONO;
                        mask = 0x3f;
                        break;
@@ -759,7 +800,7 @@ void cx88_set_stereo(struct cx8800_dev *dev, u32 mode)
                        mask = 0x3f;
                        break;
                }
-               break;  
+               break;
        }
 
        if (UNSET != ctl) {
@@ -774,32 +815,33 @@ void cx88_set_stereo(struct cx8800_dev *dev, u32 mode)
        return;
 }
 
-/* just monitor the audio status for now ... */
 int cx88_audio_thread(void *data)
 {
-       struct cx8800_dev *dev = data;
+       struct cx88_core *core = data;
        struct v4l2_tuner t;
 
-       daemonize("msp3400");
-       allow_signal(SIGTERM);
        dprintk("cx88: tvaudio thread started\n");
-
        for (;;) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ*3);
-               if (signal_pending(current))
-                       break;
-               if (dev->shutdown)
+               if (kthread_should_stop())
                        break;
 
+               /* just monitor the audio status for now ... */
                memset(&t,0,sizeof(t));
-               cx88_get_stereo(dev,&t);
+               cx88_get_stereo(core,&t);
+               msleep_interruptible(1000);
        }
 
        dprintk("cx88: tvaudio thread exiting\n");
-        complete_and_exit(&dev->texit, 0);
+       return 0;
 }
 
+/* ----------------------------------------------------------- */
+
+EXPORT_SYMBOL(cx88_set_tvaudio);
+EXPORT_SYMBOL(cx88_set_stereo);
+EXPORT_SYMBOL(cx88_get_stereo);
+EXPORT_SYMBOL(cx88_audio_thread);
+
 /*
  * Local variables:
  * c-basic-offset: 8