mirror of
https://github.com/adulau/aha.git
synced 2025-01-01 13:46:24 +00:00
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: V4L/DVB (9624): CVE-2008-5033: fix OOPS on tvaudio when controlling bass/treble V4L/DVB (9623): tvaudio: Improve debug msg by printing something more human V4L/DVB (9622): tvaudio: Improve comments and remove a unneeded prototype V4L/DVB (9621): Avoid writing outside shadow.bytes[] array V4L/DVB (9620): tvaudio: use a direct reference for chip description V4L/DVB (9619): tvaudio: update initial comments V4L/DVB (9618): tvaudio: add additional logic to avoid OOPS V4L/DVB (9617): tvtime: remove generic_checkmode callback V4L/DVB (9616): tvaudio: cleanup - group all callbacks together V4L/DVB (9615): tvaudio: instead of using a magic number, use ARRAY_SIZE V4L/DVB (9613): tvaudio: fix a memory leak
This commit is contained in:
commit
6ca2cb9937
1 changed files with 149 additions and 82 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* experimental driver for simple i2c audio chips.
|
||||
* Driver for simple i2c audio chips.
|
||||
*
|
||||
* Copyright (c) 2000 Gerd Knorr
|
||||
* based on code by:
|
||||
|
@ -7,6 +7,10 @@
|
|||
* Steve VanDeBogart (vandebo@uclink.berkeley.edu)
|
||||
* Greg Alexander (galexand@acm.org)
|
||||
*
|
||||
* Copyright(c) 2005-2008 Mauro Carvalho Chehab
|
||||
* - Some cleanups, code fixes, etc
|
||||
* - Convert it to V4L2 API
|
||||
*
|
||||
* This code is placed under the terms of the GNU General Public License
|
||||
*
|
||||
* OPTIONS:
|
||||
|
@ -30,6 +34,7 @@
|
|||
|
||||
#include <media/tvaudio.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
|
||||
|
@ -58,7 +63,6 @@ typedef int (*checkit)(struct CHIPSTATE*);
|
|||
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 {
|
||||
|
@ -79,6 +83,7 @@ struct CHIPDESC {
|
|||
#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;
|
||||
|
@ -96,23 +101,20 @@ struct CHIPDESC {
|
|||
getmode getmode;
|
||||
setmode setmode;
|
||||
|
||||
/* check / autoswitch audio after channel switches */
|
||||
checkmode checkmode;
|
||||
|
||||
/* input switch register + values for v4l inputs */
|
||||
int inputreg;
|
||||
int inputmap[4];
|
||||
int inputmute;
|
||||
int inputmask;
|
||||
};
|
||||
static struct CHIPDESC chiplist[];
|
||||
|
||||
/* current state of the chip */
|
||||
struct CHIPSTATE {
|
||||
struct i2c_client *c;
|
||||
|
||||
/* index into CHIPDESC array */
|
||||
int type;
|
||||
/* chip-specific description - should point to
|
||||
an entry at CHIPDESC table */
|
||||
struct CHIPDESC *desc;
|
||||
|
||||
/* shadow register set */
|
||||
audiocmd shadow;
|
||||
|
@ -152,7 +154,7 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
|
|||
{
|
||||
unsigned char buffer[2];
|
||||
|
||||
if (-1 == subaddr) {
|
||||
if (subaddr < 0) {
|
||||
v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n",
|
||||
chip->c->name, val);
|
||||
chip->shadow.bytes[1] = val;
|
||||
|
@ -163,6 +165,13 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
|
|||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
|
||||
v4l_info(chip->c,
|
||||
"Tried to access a non-existent register: %d\n",
|
||||
subaddr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n",
|
||||
chip->c->name, subaddr, val);
|
||||
chip->shadow.bytes[subaddr+1] = val;
|
||||
|
@ -177,12 +186,20 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int chip_write_masked(struct CHIPSTATE *chip, int subaddr, int val, int mask)
|
||||
static int chip_write_masked(struct CHIPSTATE *chip,
|
||||
int subaddr, int val, int mask)
|
||||
{
|
||||
if (mask != 0) {
|
||||
if (-1 == subaddr) {
|
||||
if (subaddr < 0) {
|
||||
val = (chip->shadow.bytes[1] & ~mask) | (val & mask);
|
||||
} else {
|
||||
if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
|
||||
v4l_info(chip->c,
|
||||
"Tried to access a non-existent register: %d\n",
|
||||
subaddr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val = (chip->shadow.bytes[subaddr+1] & ~mask) | (val & mask);
|
||||
}
|
||||
}
|
||||
|
@ -228,6 +245,15 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
|
|||
if (0 == cmd->count)
|
||||
return 0;
|
||||
|
||||
if (cmd->count + cmd->bytes[0] - 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
|
||||
v4l_info(chip->c,
|
||||
"Tried to access a non-existent register range: %d to %d\n",
|
||||
cmd->bytes[0] + 1, cmd->bytes[0] + cmd->count - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* FIXME: it seems that the shadow bytes are wrong bellow !*/
|
||||
|
||||
/* update our shadow register set; print bytes if (debug > 0) */
|
||||
v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:",
|
||||
chip->c->name, name,cmd->bytes[0]);
|
||||
|
@ -263,7 +289,8 @@ static void chip_thread_wake(unsigned long data)
|
|||
static int chip_thread(void *data)
|
||||
{
|
||||
struct CHIPSTATE *chip = data;
|
||||
struct CHIPDESC *desc = chiplist + chip->type;
|
||||
struct CHIPDESC *desc = chip->desc;
|
||||
int mode;
|
||||
|
||||
v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name);
|
||||
set_freezable();
|
||||
|
@ -282,7 +309,26 @@ static int chip_thread(void *data)
|
|||
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));
|
||||
|
@ -292,29 +338,6 @@ static int chip_thread(void *data)
|
|||
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 */
|
||||
|
||||
|
@ -777,7 +800,7 @@ static struct tda9874a_MODES {
|
|||
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 }} },
|
||||
|
@ -791,7 +814,7 @@ static struct tda9874a_MODES {
|
|||
{ 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 }} }
|
||||
|
@ -981,7 +1004,7 @@ static int tda9874a_initialize(struct CHIPSTATE *chip)
|
|||
{
|
||||
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;
|
||||
|
@ -1089,7 +1112,7 @@ static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
|
|||
|
||||
static int tda8425_initialize(struct CHIPSTATE *chip)
|
||||
{
|
||||
struct CHIPDESC *desc = chiplist + chip->type;
|
||||
struct CHIPDESC *desc = chip->desc;
|
||||
int inputmap[4] = { /* tuner */ TDA8425_S1_CH2, /* radio */ TDA8425_S1_CH1,
|
||||
/* extern */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF};
|
||||
|
||||
|
@ -1259,27 +1282,28 @@ static struct CHIPDESC chiplist[] = {
|
|||
.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,
|
||||
|
@ -1290,15 +1314,16 @@ static struct CHIPDESC chiplist[] = {
|
|||
},
|
||||
{
|
||||
.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",
|
||||
|
@ -1324,10 +1349,11 @@ static struct CHIPDESC chiplist[] = {
|
|||
.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,
|
||||
|
||||
|
@ -1348,6 +1374,8 @@ static struct CHIPDESC chiplist[] = {
|
|||
.rightreg = TEA6300_VL,
|
||||
.bassreg = TEA6300_BA,
|
||||
.treblereg = TEA6300_TR,
|
||||
|
||||
/* callbacks */
|
||||
.volfunc = tea6300_shift10,
|
||||
.bassfunc = tea6300_shift12,
|
||||
.treblefunc = tea6300_shift12,
|
||||
|
@ -1358,7 +1386,6 @@ static struct CHIPDESC chiplist[] = {
|
|||
},
|
||||
{
|
||||
.name = "tea6320",
|
||||
.initialize = tea6320_initialize,
|
||||
.insmodopt = &tea6320,
|
||||
.addr_lo = I2C_ADDR_TEA6300 >> 1,
|
||||
.addr_hi = I2C_ADDR_TEA6300 >> 1,
|
||||
|
@ -1369,6 +1396,9 @@ static struct CHIPDESC chiplist[] = {
|
|||
.rightreg = TEA6320_V,
|
||||
.bassreg = TEA6320_BA,
|
||||
.treblereg = TEA6320_TR,
|
||||
|
||||
/* callbacks */
|
||||
.initialize = tea6320_initialize,
|
||||
.volfunc = tea6320_volume,
|
||||
.bassfunc = tea6320_shift11,
|
||||
.treblefunc = tea6320_shift11,
|
||||
|
@ -1401,16 +1431,18 @@ static struct CHIPDESC chiplist[] = {
|
|||
.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)",
|
||||
|
@ -1434,10 +1466,11 @@ static struct CHIPDESC chiplist[] = {
|
|||
.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}},
|
||||
},
|
||||
|
@ -1481,6 +1514,7 @@ static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
}
|
||||
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);
|
||||
|
@ -1494,7 +1528,7 @@ static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
/* fill required data structures */
|
||||
if (!id)
|
||||
strlcpy(client->name, desc->name, I2C_NAME_SIZE);
|
||||
chip->type = desc-chiplist;
|
||||
chip->desc = desc;
|
||||
chip->shadow.count = desc->registers+1;
|
||||
chip->prevmode = -1;
|
||||
chip->audmode = V4L2_TUNER_MODE_LANG1;
|
||||
|
@ -1506,20 +1540,49 @@ static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
chip_cmd(chip,"init",&desc->init);
|
||||
|
||||
if (desc->flags & CHIP_HAS_VOLUME) {
|
||||
chip->left = desc->leftinit ? desc->leftinit : 65535;
|
||||
chip->right = desc->rightinit ? desc->rightinit : 65535;
|
||||
chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
|
||||
chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
|
||||
if (!desc->volfunc) {
|
||||
/* This shouldn't be happen. Warn user, but keep working
|
||||
without volume controls
|
||||
*/
|
||||
v4l_info(chip->c, "volume callback undefined!\n");
|
||||
desc->flags &= ~CHIP_HAS_VOLUME;
|
||||
} else {
|
||||
chip->left = desc->leftinit ? desc->leftinit : 65535;
|
||||
chip->right = desc->rightinit ? desc->rightinit : 65535;
|
||||
chip_write(chip, desc->leftreg,
|
||||
desc->volfunc(chip->left));
|
||||
chip_write(chip, desc->rightreg,
|
||||
desc->volfunc(chip->right));
|
||||
}
|
||||
}
|
||||
if (desc->flags & CHIP_HAS_BASSTREBLE) {
|
||||
chip->treble = desc->trebleinit ? desc->trebleinit : 32768;
|
||||
chip->bass = desc->bassinit ? desc->bassinit : 32768;
|
||||
chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
|
||||
chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
|
||||
if (!desc->bassfunc || !desc->treblefunc) {
|
||||
/* This shouldn't be happen. Warn user, but keep working
|
||||
without bass/treble controls
|
||||
*/
|
||||
v4l_info(chip->c, "bass/treble callbacks undefined!\n");
|
||||
desc->flags &= ~CHIP_HAS_BASSTREBLE;
|
||||
} else {
|
||||
chip->treble = desc->trebleinit ?
|
||||
desc->trebleinit : 32768;
|
||||
chip->bass = desc->bassinit ?
|
||||
desc->bassinit : 32768;
|
||||
chip_write(chip, desc->bassreg,
|
||||
desc->bassfunc(chip->bass));
|
||||
chip_write(chip, desc->treblereg,
|
||||
desc->treblefunc(chip->treble));
|
||||
}
|
||||
}
|
||||
|
||||
chip->thread = NULL;
|
||||
if (desc->checkmode) {
|
||||
if (desc->flags & CHIP_NEED_CHECKMODE) {
|
||||
if (!desc->getmode || !desc->setmode) {
|
||||
/* This shouldn't be happen. Warn user, but keep working
|
||||
without kthread
|
||||
*/
|
||||
v4l_info(chip->c, "set/get mode callbacks undefined!\n");
|
||||
return 0;
|
||||
}
|
||||
/* start async thread */
|
||||
init_timer(&chip->wt);
|
||||
chip->wt.function = chip_thread_wake;
|
||||
|
@ -1552,7 +1615,7 @@ static int chip_remove(struct i2c_client *client)
|
|||
static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct CHIPDESC *desc = chiplist + chip->type;
|
||||
struct CHIPDESC *desc = chip->desc;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
|
@ -1576,13 +1639,13 @@ static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
|
|||
return 0;
|
||||
}
|
||||
case V4L2_CID_AUDIO_BASS:
|
||||
if (desc->flags & CHIP_HAS_BASSTREBLE)
|
||||
if (!(desc->flags & CHIP_HAS_BASSTREBLE))
|
||||
break;
|
||||
ctrl->value = chip->bass;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_TREBLE:
|
||||
if (desc->flags & CHIP_HAS_BASSTREBLE)
|
||||
return -EINVAL;
|
||||
if (!(desc->flags & CHIP_HAS_BASSTREBLE))
|
||||
break;
|
||||
ctrl->value = chip->treble;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1592,7 +1655,7 @@ static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
|
|||
static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct CHIPDESC *desc = chiplist + chip->type;
|
||||
struct CHIPDESC *desc = chip->desc;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
|
@ -1642,16 +1705,15 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
|
|||
return 0;
|
||||
}
|
||||
case V4L2_CID_AUDIO_BASS:
|
||||
if (desc->flags & CHIP_HAS_BASSTREBLE)
|
||||
if (!(desc->flags & CHIP_HAS_BASSTREBLE))
|
||||
break;
|
||||
chip->bass = ctrl->value;
|
||||
chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
|
||||
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_TREBLE:
|
||||
if (desc->flags & CHIP_HAS_BASSTREBLE)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(desc->flags & CHIP_HAS_BASSTREBLE))
|
||||
break;
|
||||
chip->treble = ctrl->value;
|
||||
chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
|
||||
|
||||
|
@ -1668,9 +1730,12 @@ static int chip_command(struct i2c_client *client,
|
|||
unsigned int cmd, void *arg)
|
||||
{
|
||||
struct CHIPSTATE *chip = i2c_get_clientdata(client);
|
||||
struct CHIPDESC *desc = chiplist + chip->type;
|
||||
struct CHIPDESC *desc = chip->desc;
|
||||
|
||||
v4l_dbg(1, debug, chip->c, "%s: chip_command 0x%x\n", chip->c->name, cmd);
|
||||
if (debug > 0) {
|
||||
v4l_i2c_print_ioctl(chip->c, cmd);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case AUDC_SET_RADIO:
|
||||
|
@ -1695,7 +1760,7 @@ static int chip_command(struct i2c_client *client,
|
|||
break;
|
||||
case V4L2_CID_AUDIO_BASS:
|
||||
case V4L2_CID_AUDIO_TREBLE:
|
||||
if (desc->flags & CHIP_HAS_BASSTREBLE)
|
||||
if (!(desc->flags & CHIP_HAS_BASSTREBLE))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
|
@ -1792,12 +1857,20 @@ static int chip_command(struct i2c_client *client,
|
|||
break;
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
chip->mode = 0; /* automatic */
|
||||
if (desc->checkmode && desc->setmode) {
|
||||
|
||||
/* For chips that provide getmode and setmode, and doesn't
|
||||
automatically follows the stereo carrier, a kthread is
|
||||
created to set the audio standard. In this case, when then
|
||||
the video channel is changed, tvaudio starts on MONO mode.
|
||||
After waiting for 2 seconds, the kernel thread is called,
|
||||
to follow whatever audio standard is pointed by the
|
||||
audio carrier.
|
||||
*/
|
||||
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;
|
||||
|
||||
|
@ -1836,9 +1909,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
|||
.legacy_probe = chip_legacy_probe,
|
||||
.id_table = chip_id,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue