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) {