The patch number 9617 was added via Mauro Carvalho Chehab <[EMAIL PROTECTED]>
to http://linuxtv.org/hg/v4l-dvb master development tree.

Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel

If anyone has any objections, please let us know by sending a message to:
        [EMAIL PROTECTED]

------

From: Mauro Carvalho Chehab  <[EMAIL PROTECTED]>
tvtime: avoid OOPS at generic_checkmode()


generic_checkmode() were called, via a callback, for some tvaudio chips.
There's just one callback code used on all those boards. So, it makes no
sense on keeping this as a callback.

Since there were some OOPS reported on tvaudio on kerneloops.org, this
patch removes this callback, adding the code at the only place were it
is called: inside chip_tread. A flag were added to indicate the need for
a kernel thread to set stereo mode on cards that needs it.

Priority: high

Signed-off-by: Mauro Carvalho Chehab <[EMAIL PROTECTED]>


---

 linux/drivers/media/video/tvaudio.c |   71 +++++++++++++---------------
 1 file changed, 35 insertions(+), 36 deletions(-)

diff -r 362efac2527a -r f8a8e0909f40 linux/drivers/media/video/tvaudio.c
--- a/linux/drivers/media/video/tvaudio.c       Thu Nov 13 14:14:15 2008 -0200
+++ b/linux/drivers/media/video/tvaudio.c       Thu Nov 13 14:55:39 2008 -0200
@@ -61,7 +61,6 @@ typedef int  (*initialize)(struct CHIPST
 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 {
@@ -82,6 +81,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;
@@ -98,9 +98,6 @@ struct CHIPDESC {
        /* get/set mode */
        getmode  getmode;
        setmode  setmode;
-
-       /* check / autoswitch audio after channel switches */
-       checkmode  checkmode;
 
        /* input switch register + values for v4l inputs */
        int  inputreg;
@@ -267,6 +264,7 @@ static int chip_thread(void *data)
 {
        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();
@@ -285,7 +283,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));
@@ -293,29 +310,6 @@ static int chip_thread(void *data)
 
        v4l_dbg(1, debug, chip->c, "%s: thread exiting\n", chip->c->name);
        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);
 }
 
 /* ---------------------------------------------------------------------- */
@@ -1267,12 +1261,12 @@ 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 */} }
@@ -1283,13 +1277,12 @@ static struct CHIPDESC chiplist[] = {
                .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,
@@ -1303,13 +1296,13 @@ static struct CHIPDESC chiplist[] = {
                .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",
@@ -1452,11 +1445,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}},
        },
@@ -1543,7 +1536,7 @@ static int chip_probe(struct i2c_client 
        }
 
        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;
@@ -1816,12 +1809,18 @@ static int chip_command(struct i2c_clien
                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;
 


---

Patch is available at: 
http://linuxtv.org/hg/v4l-dvb/rev/f8a8e0909f409eb8f7fac25994da1dba930aa36a

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to