I tracked down a possible segfault condition which could lock a device due to bad ioctl input. In this case it was using radio -P on a PVR-250. ivtv-streams never does a bounds check when accessing its streams array, so I've added the check in many places (not all are needed due to call hiearchys). I've also added code to set tda9887=0 if a non-NTSC PVR-150 is detected. I'm pretty sure this is a safe thing to do and should prevent requiring the module option to be set manually. Finally, I added code to set port1=0 port2=0 (enable output) on the tda9887 on unpause_and_resume(). I believe this is part of the magic of the black magic patch and hopefully should further reduce sound problems on PVR-150s in PAL-land (SECAM we'll see). Users who got mediocre sound by setting the qss module parameter might want to try removing it after this patch.

Whew! Busy day.
Index: driver/ivtv-i2c.c
===================================================================
--- driver/ivtv-i2c.c   (revision 329)
+++ driver/ivtv-i2c.c   (working copy)
@@ -201,7 +201,7 @@
                           "skipping client %d, addr 0x%02x\n", i,
                           (u8) client->addr);
        }
-       IVTV_DEBUG(IVTV_DEBUG_ERR, "i2c client addr: 0x%02x not found for 
command %u!\n",
+       IVTV_DEBUG(IVTV_DEBUG_ERR, "i2c client addr: 0x%02x not found for 
command 0x%x!\n",
                   (u8) addr, cmd);
        up(&itv->i2c_lock);
        return -ENODEV;
Index: driver/ivtv-fileops.c
===================================================================
--- driver/ivtv-fileops.c       (revision 329)
+++ driver/ivtv-fileops.c       (working copy)
@@ -1602,6 +1602,11 @@
        IVTV_DEBUG(IVTV_DEBUG_INFO, "Disabling digitizer\n");
        dig = 0;
        itv->card->video_dec_func(itv, DECODER_ENABLE_OUTPUT, &dig);
+       
+       if (tda9887 == 0) {
+               int config = 0;
+               ivtv_tda9887(itv, TDA9887_SET_CONFIG, &config);
+       }
 }
 
 void unmute_and_resume(struct ivtv *itv, int sleep)
@@ -1629,6 +1634,11 @@
        if (sleep)
                ivtv_sleep_timeout(HZ / 10, 0);
 
+       if (tda9887 == 0) {
+               int config = TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE;
+               ivtv_tda9887(itv, TDA9887_SET_CONFIG, &config);
+       }
+
        /* Unmute */
        ivtv_audio_set_mute(itv, 0);
        IVTV_DEBUG(IVTV_DEBUG_INFO, "Finished with Mute\n");
Index: driver/ivtv-streams.c
===================================================================
--- driver/ivtv-streams.c       (revision 329)
+++ driver/ivtv-streams.c       (working copy)
@@ -427,9 +427,25 @@
        return -ENOMEM;
 }
 
+static struct ivtv_stream *ivtv_stream_safeget(const char *desc, 
+               struct ivtv *itv, int type)
+{
+       if (type >= itv->streamcount) {
+               IVTV_DEBUG(IVTV_DEBUG_ERR, 
+                       "%s accessing uninitialied %s stream\n",
+                       desc, ivtv_stream_name(type));
+               return NULL;
+       }
+
+       return &itv->streams[type];
+}
+
 void ivtv_unreg_dev(struct ivtv *itv, int stream)
 {
-       struct ivtv_stream *s = &itv->streams[stream];
+       struct ivtv_stream *s = ivtv_stream_safeget(
+               "ivtv_unreg_dev", itv, stream);
+       if (s == NULL)
+               return;
 
        if (s->v4l2dev == NULL)
                return;
@@ -463,8 +479,13 @@
 
 void ivtv_setup_v4l2_encode_stream(struct ivtv *itv, int type)
 {
+       struct ivtv_stream *s = ivtv_stream_safeget(
+               "ivtv_setup_v4l2_encode_stream", itv, type);
+       if (s == NULL)
+               return;
+
        /* streams_lock must be held */
-       IVTV_ASSERT(ivtv_sem_count(&itv->streams[type].mlock) <= 0);
+       IVTV_ASSERT(ivtv_sem_count(&s->mlock) <= 0);
 
        /* assign stream type */
        ivtv_vapi(itv, IVTV_API_ASSIGN_STREAM_TYPE, 1, itv->codec.stream_type);
@@ -531,8 +552,10 @@
 void init_decoder(struct ivtv *itv) 
 {
        int x = 0;
-       struct ivtv_stream *stream =
-           &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
+       struct ivtv_stream *stream = ivtv_stream_safeget(
+               "init_decoder", itv, IVTV_DEC_STREAM_TYPE_MPG);
+       if (stream == NULL)
+               return;
 
         /* Setup Decoder */
        down(&stream->mlock);
@@ -587,11 +610,14 @@
 int ivtv_passthrough_mode(struct ivtv *itv, int enable)
 {
        int x;
-       struct ivtv_stream *yuv_stream =
-           &itv->streams[IVTV_ENC_STREAM_TYPE_YUV];
-       struct ivtv_stream *dec_stream =
-           &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
+       struct ivtv_stream *yuv_stream = ivtv_stream_safeget(
+               "ivtv_passthrough_mode", itv, IVTV_ENC_STREAM_TYPE_YUV);
+       struct ivtv_stream *dec_stream = ivtv_stream_safeget(
+               "ivtv_passthrough_mode", itv, IVTV_DEC_STREAM_TYPE_YUV);
 
+       if (yuv_stream == NULL || dec_stream == NULL)
+               return -EINVAL;
+
        IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv ioctl: Select passthrough mode\n");
 
        /* Prevent others from starting/stopping streams while we
@@ -604,7 +630,7 @@
                        return -EBUSY;
                }
 
-               down(&dec_stream->mlock);
+               down(&dec_stream->mlock); 
                set_bit(IVTV_F_I_PASSTHROUGH, &itv->i_flags);
 
                /* Fully initialize stream, and then unflag init */
@@ -851,9 +877,13 @@
        u32 data[IVTV_MBOX_MAX_DATA], result;
        int x = 0;
        int captype = 0, subtype = 0;
-       struct ivtv_stream *st = &itv->streams[type];
+       struct ivtv_stream *st = ivtv_stream_safeget(
+               "ivtv_start_v4l2_encode_stream", itv, type);
        int enable_passthrough = 0;
 
+       if (st == NULL)
+               return -EINVAL;
+
        /* Lock */
        down(&st->mlock);
 
@@ -1078,11 +1108,15 @@
 {
        u32 data[IVTV_MBOX_MAX_DATA], result;
        int x;
+       struct ivtv_stream *s = ivtv_stream_safeget(
+               "ivtv_setup_v4l2_decode_stream", itv, type);
+       if (s == NULL)
+               return -EINVAL;
 
        IVTV_DEBUG(IVTV_DEBUG_INFO, "Setting some initial decoder settings\n");
 
        /* streams_lock must be held */
-       IVTV_ASSERT(ivtv_sem_count(&itv->streams[type].mlock) <= 0);
+       IVTV_ASSERT(ivtv_sem_count(&s->mlock) <= 0);
 
        /* disable VBI signals, if the MPEG stream contains VBI data,
           then that data will be processed automatically for you. */
@@ -1150,13 +1184,14 @@
 
 int ivtv_start_v4l2_decode_stream(struct ivtv *itv, int type)
 {
-       struct ivtv_stream *stream;
        int x;
        int yuv_num = 0;
+       struct ivtv_stream *stream = ivtv_stream_safeget(
+               "ivtv_start_v4l2_decode_stream", itv, type);
 
-       stream = &itv->streams[type];
+       if (stream == NULL)
+               return -EINVAL;
 
-
        /* Lock Stream */
        down(&stream->mlock);
 
@@ -1278,7 +1313,8 @@
 
 int ivtv_stop_capture(struct ivtv *itv, int type)
 {
-       struct ivtv_stream *st = &itv->streams[type];
+       struct ivtv_stream *st = ivtv_stream_safeget(
+               "ivtv_stop_capture", itv, type);
        int cap_type;
        unsigned long then;
        int x;
@@ -1286,6 +1322,9 @@
        u32 data[IVTV_MBOX_MAX_DATA], result;
        int thread_to_stop = 0;
 
+       if (st == NULL)
+               return -EINVAL;
+
        DECLARE_WAITQUEUE(wait, current);
 
        /* This function assumes that you are allowed to stop the capture
@@ -1524,11 +1563,15 @@
 
 int ivtv_stop_v4l2_decode_stream(struct ivtv *itv, int type)
 {
-       struct ivtv_stream *st = &itv->streams[type];
+       struct ivtv_stream *st = ivtv_stream_safeget(
+               "ivtv_stop_v4l2_decode_stream", itv, type);
        int count, maxcount = 30;
        int no_stop = itv->dec_options.no_stop;
        int hide_last_frame = itv->dec_options.hide_last_frame;
 
+       if (st == NULL)
+               return -EINVAL;
+
        if (type == IVTV_DEC_STREAM_TYPE_YUV) {
                no_stop = 1;
                hide_last_frame = 0;
Index: driver/ivtv-driver.c
===================================================================
--- driver/ivtv-driver.c        (revision 329)
+++ driver/ivtv-driver.c        (working copy)
@@ -1001,8 +1001,11 @@
                if (itv->card->type == IVTV_CARD_PVR_150 ||
                    itv->card->type == IVTV_CARD_PG600) {
                        ivtv_request_module("cx25840");
-                       if (itv->card->type == IVTV_CARD_PVR_150)
+                       if (itv->card->type == IVTV_CARD_PVR_150) {
                                ivtv_request_module("wm8775");
+                               if (itv->std != V4L2_STD_NTSC && tda9887 == -1)
+                                       tda9887 = 0;
+                       }
                } else
                        ivtv_request_module("saa7115");
                if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {

Reply via email to