typedef int (*initialize)(struct CHIPSTATE*);
typedef int (*getmode)(struct CHIPSTATE*);
typedef void (*setmode)(struct CHIPSTATE*, int mode);
-typedef void (*checkmode)(struct CHIPSTATE*);
/* i2c command */
typedef struct AUDIOCMD {
#define CHIP_HAS_VOLUME 1
#define CHIP_HAS_BASSTREBLE 2
#define CHIP_HAS_INPUTSEL 4
+#define CHIP_NEED_CHECKMODE 8
/* various i2c command sequences */
audiocmd init;
getmode getmode;
setmode setmode;
- /* check / autoswitch audio after channel switches */
- checkmode checkmode;
-
/* input switch register + values for v4l inputs */
int inputreg;
int inputmap[4];
{
struct CHIPSTATE *chip = data;
struct CHIPDESC *desc = chiplist + chip->type;
+ int mode;
v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name);
set_freezable();
continue;
/* have a look what's going on */
- desc->checkmode(chip);
+ mode = desc->getmode(chip);
+ if (mode == chip->prevmode)
+ continue;
+
+ /* chip detected a new audio mode - set it */
+ v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n",
+ chip->c->name);
+
+ chip->prevmode = mode;
+
+ if (mode & V4L2_TUNER_MODE_STEREO)
+ desc->setmode(chip, V4L2_TUNER_MODE_STEREO);
+ if (mode & V4L2_TUNER_MODE_LANG1_LANG2)
+ desc->setmode(chip, V4L2_TUNER_MODE_STEREO);
+ else if (mode & V4L2_TUNER_MODE_LANG1)
+ desc->setmode(chip, V4L2_TUNER_MODE_LANG1);
+ else if (mode & V4L2_TUNER_MODE_LANG2)
+ desc->setmode(chip, V4L2_TUNER_MODE_LANG2);
+ else
+ desc->setmode(chip, V4L2_TUNER_MODE_MONO);
/* schedule next check */
mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
return 0;
}
-static void generic_checkmode(struct CHIPSTATE *chip)
-{
- struct CHIPDESC *desc = chiplist + chip->type;
- int mode = desc->getmode(chip);
-
- if (mode == chip->prevmode)
- return;
-
- v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n", chip->c->name);
- chip->prevmode = mode;
-
- if (mode & V4L2_TUNER_MODE_STEREO)
- desc->setmode(chip,V4L2_TUNER_MODE_STEREO);
- if (mode & V4L2_TUNER_MODE_LANG1_LANG2)
- desc->setmode(chip,V4L2_TUNER_MODE_STEREO);
- else if (mode & V4L2_TUNER_MODE_LANG1)
- desc->setmode(chip,V4L2_TUNER_MODE_LANG1);
- else if (mode & V4L2_TUNER_MODE_LANG2)
- desc->setmode(chip,V4L2_TUNER_MODE_LANG2);
- else
- desc->setmode(chip,V4L2_TUNER_MODE_MONO);
-}
-
/* ---------------------------------------------------------------------- */
/* audio chip descriptions - defines+functions for tda9840 */
char *name;
audiocmd cmd;
} tda9874a_modelist[9] = {
- { "A2, B/G",
+ { "A2, B/G", /* default */
{ 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x77,0xA0,0x00, 0x00,0x00 }} },
{ "A2, M (Korea)",
{ 9, { TDA9874A_C1FRA, 0x5D,0xC0,0x00, 0x62,0x6A,0xAA, 0x20,0x22 }} },
{ 9, { TDA9874A_C1FRA, 0x7D,0x00,0x00, 0x88,0x8A,0xAA, 0x08,0x33 }} },
{ "NICAM, B/G",
{ 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x79,0xEA,0xAA, 0x08,0x33 }} },
- { "NICAM, D/K", /* default */
+ { "NICAM, D/K",
{ 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x08,0x33 }} },
{ "NICAM, L",
{ 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x09,0x33 }} }
{
if (tda9874a_SIF > 2)
tda9874a_SIF = 1;
- if (tda9874a_STD > 8)
+ if (tda9874a_STD >= ARRAY_SIZE(tda9874a_modelist))
tda9874a_STD = 0;
if(tda9874a_AMSEL > 1)
tda9874a_AMSEL = 0;
.addr_lo = I2C_ADDR_TDA9840 >> 1,
.addr_hi = I2C_ADDR_TDA9840 >> 1,
.registers = 5,
+ .flags = CHIP_NEED_CHECKMODE,
+ /* callbacks */
.checkit = tda9840_checkit,
.getmode = tda9840_getmode,
.setmode = tda9840_setmode,
- .checkmode = generic_checkmode,
.init = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
/* ,TDA9840_SW, TDA9840_MONO */} }
},
{
.name = "tda9873h",
- .checkit = tda9873_checkit,
.insmodopt = &tda9873,
.addr_lo = I2C_ADDR_TDA985x_L >> 1,
.addr_hi = I2C_ADDR_TDA985x_H >> 1,
.registers = 3,
- .flags = CHIP_HAS_INPUTSEL,
+ .flags = CHIP_HAS_INPUTSEL | CHIP_NEED_CHECKMODE,
+ /* callbacks */
+ .checkit = tda9873_checkit,
.getmode = tda9873_getmode,
.setmode = tda9873_setmode,
- .checkmode = generic_checkmode,
.init = { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
.inputreg = TDA9873_SW,
},
{
.name = "tda9874h/a",
- .checkit = tda9874a_checkit,
- .initialize = tda9874a_initialize,
.insmodopt = &tda9874a,
.addr_lo = I2C_ADDR_TDA9874 >> 1,
.addr_hi = I2C_ADDR_TDA9874 >> 1,
+ .flags = CHIP_NEED_CHECKMODE,
+ /* callbacks */
+ .initialize = tda9874a_initialize,
+ .checkit = tda9874a_checkit,
.getmode = tda9874a_getmode,
.setmode = tda9874a_setmode,
- .checkmode = generic_checkmode,
},
{
.name = "tda9850",
.rightreg = TDA9855_VR,
.bassreg = TDA9855_BA,
.treblereg = TDA9855_TR,
+
+ /* callbacks */
.volfunc = tda9855_volume,
.bassfunc = tda9855_bass,
.treblefunc = tda9855_treble,
-
.getmode = tda985x_getmode,
.setmode = tda985x_setmode,
.rightreg = TEA6300_VL,
.bassreg = TEA6300_BA,
.treblereg = TEA6300_TR,
+
+ /* callbacks */
.volfunc = tea6300_shift10,
.bassfunc = tea6300_shift12,
.treblefunc = tea6300_shift12,
},
{
.name = "tea6320",
- .initialize = tea6320_initialize,
.insmodopt = &tea6320,
.addr_lo = I2C_ADDR_TEA6300 >> 1,
.addr_hi = I2C_ADDR_TEA6300 >> 1,
.rightreg = TEA6320_V,
.bassreg = TEA6320_BA,
.treblereg = TEA6320_TR,
+
+ /* callbacks */
+ .initialize = tea6320_initialize,
.volfunc = tea6320_volume,
.bassfunc = tea6320_shift11,
.treblefunc = tea6320_shift11,
.rightreg = TDA8425_VR,
.bassreg = TDA8425_BA,
.treblereg = TDA8425_TR,
+
+ /* callbacks */
+ .initialize = tda8425_initialize,
.volfunc = tda8425_shift10,
.bassfunc = tda8425_shift12,
.treblefunc = tda8425_shift12,
+ .setmode = tda8425_setmode,
.inputreg = TDA8425_S1,
.inputmap = { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },
.inputmute = TDA8425_S1_OFF,
- .setmode = tda8425_setmode,
- .initialize = tda8425_initialize,
},
{
.name = "pic16c54 (PV951)",
.addr_lo = I2C_ADDR_TDA9840 >> 1,
.addr_hi = I2C_ADDR_TDA9840 >> 1,
.registers = 2,
+ .flags = CHIP_NEED_CHECKMODE,
+ /* callbacks */
.getmode = ta8874z_getmode,
.setmode = ta8874z_setmode,
- .checkmode = generic_checkmode,
.init = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
},
}
if (desc->name == NULL) {
v4l_dbg(1, debug, client, "no matching chip description found\n");
+ kfree(chip);
return -EIO;
}
v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
}
chip->thread = NULL;
- if (desc->checkmode) {
+ if (desc->flags & CHIP_NEED_CHECKMODE) {
/* start async thread */
init_timer(&chip->wt);
chip->wt.function = chip_thread_wake;
break;
case VIDIOC_S_FREQUENCY:
chip->mode = 0; /* automatic */
- if (desc->checkmode && desc->setmode) {
+
+ /* For chips that provide getmode, setmode and checkmode,
+ a kthread is created to automatically to set the audio
+ standard. In this case, start with MONO and wait 2 seconds
+ for the decoding to stablize. Then, run kthread to change
+ to stereo, if carrier detected.
+ */
+ if (chip->thread) {
desc->setmode(chip,V4L2_TUNER_MODE_MONO);
if (chip->prevmode != V4L2_TUNER_MODE_MONO)
chip->prevmode = -1; /* reset previous mode */
mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
- /* the thread will call checkmode() later */
}
break;