/*
+ $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]
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)
/* ----------------------------------------------------------- */
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;
}
}
-static void set_audio_start(struct cx8800_dev *dev,
+static void set_audio_start(struct cx88_core *core,
u32 mode, u32 ctl)
{
// mute
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;
/* ----------------------------------------------------------- */
-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 */
// 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 */
{ /* 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[] = {
};
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[] = {
{ /* 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 ... */
};
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)
cx_write(AUD_DEEMPH1_B0, 0x1C29);
cx_write(AUD_DEEMPH1_A1, 0x3FC66);
cx_write(AUD_DEEMPH1_B1, 0x399A);
-
+
break;
case WW_FM_DEEMPH_75:
#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", "?"};
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:
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;
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;
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;
mask = 0x3f;
break;
}
- break;
+ break;
}
if (UNSET != ctl) {
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