Commit 3562c43b authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (6045): ivtv: fix handling of INITIALIZE_INPUT fw call

The CX2341X_ENC_INITIALIZE_INPUT firmware call requires careful handling,
otherwise the computer can freeze or the top-third of the screen can start
flickering. This patch ensures that CX2341X_ENC_INITIALIZE_INPUT is called
at the right time and in the right way.

In addition the stop capture handling was improved so that the last pending
DMA transfer is also processed. Otherwise this would be the first data that
arrived when a new capture was started which is not what you want.
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent da80be21
...@@ -892,12 +892,20 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) ...@@ -892,12 +892,20 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
return -EBUSY; return -EBUSY;
} }
if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
if (atomic_read(&itv->capturing) > 0) {
/* switching to radio while capture is
in progress is not polite */
kfree(item);
return -EBUSY;
}
}
/* Mark that the radio is being used. */
set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
/* We have the radio */ /* We have the radio */
ivtv_mute(itv); ivtv_mute(itv);
/* Switch tuner to radio */ /* Switch tuner to radio */
ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL); ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL);
/* Mark that the radio is being used. */
set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
/* Select the correct audio input (i.e. radio tuner) */ /* Select the correct audio input (i.e. radio tuner) */
ivtv_audio_set_io(itv); ivtv_audio_set_io(itv);
if (itv->hw_flags & IVTV_HW_SAA711X) if (itv->hw_flags & IVTV_HW_SAA711X)
...@@ -931,13 +939,8 @@ void ivtv_mute(struct ivtv *itv) ...@@ -931,13 +939,8 @@ void ivtv_mute(struct ivtv *itv)
void ivtv_unmute(struct ivtv *itv) void ivtv_unmute(struct ivtv *itv)
{ {
/* initialize or refresh input */
if (atomic_read(&itv->capturing) == 0)
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
ivtv_msleep_timeout(100, 0);
if (atomic_read(&itv->capturing)) { if (atomic_read(&itv->capturing)) {
ivtv_msleep_timeout(100, 0);
ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0);
} }
......
...@@ -906,6 +906,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ...@@ -906,6 +906,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
IVTV_DEBUG_INFO("Input unchanged\n"); IVTV_DEBUG_INFO("Input unchanged\n");
break; break;
} }
if (atomic_read(&itv->capturing) > 0) {
return -EBUSY;
}
IVTV_DEBUG_INFO("Changing input from %d to %d\n", IVTV_DEBUG_INFO("Changing input from %d to %d\n",
itv->active_input, inp); itv->active_input, inp);
......
...@@ -554,9 +554,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) ...@@ -554,9 +554,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
clear_bit(IVTV_F_I_EOS, &itv->i_flags); clear_bit(IVTV_F_I_EOS, &itv->i_flags);
/* Initialize Digitizer for Capture */ /* Initialize Digitizer for Capture */
itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0);
ivtv_msleep_timeout(300, 1);
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
itv->video_dec_func(itv, VIDIOC_STREAMON, 0);
ivtv_msleep_timeout(100, 0);
} }
/* begin_capture */ /* begin_capture */
...@@ -713,7 +714,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) ...@@ -713,7 +714,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
int cap_type; int cap_type;
unsigned long then; unsigned long then;
int stopmode; int stopmode;
u32 data[CX2341X_MBOX_MAX_DATA];
if (s->v4l2dev == NULL) if (s->v4l2dev == NULL)
return -EINVAL; return -EINVAL;
...@@ -793,27 +793,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) ...@@ -793,27 +793,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
} }
then = jiffies; then = jiffies;
/* Make sure DMA is complete */
add_wait_queue(&s->waitq, &wait);
do {
/* check if DMA is pending */
if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */
(read_reg(IVTV_REG_DMASTATUS) & 0x02)) {
/* Check for last DMA */
ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0);
if (data[0] == 1) {
IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]);
break;
}
} else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
break;
}
} while (!ivtv_msleep_timeout(10, 1) &&
then + msecs_to_jiffies(2000) > jiffies);
set_current_state(TASK_RUNNING); /* Handle any pending interrupts */
remove_wait_queue(&s->waitq, &wait); ivtv_msleep_timeout(100, 1);
} }
atomic_dec(&itv->capturing); atomic_dec(&itv->capturing);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment