V4L/DVB (7931): cx18: allow for simultaneous digital and analog capture
The HVR-1600 can do both analog and digital capture at the same time. Due to a driver bug -EBUSY would be returned when attempting to setup an analog capture while a digital capture was already in progress. Separate the two internally. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
be303e16db
commit
31554ae599
|
@ -159,7 +159,7 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt
|
||||||
{
|
{
|
||||||
if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
|
if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (atomic_read(&cx->capturing) > 0)
|
if (atomic_read(&cx->ana_capturing) > 0)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
/* First try to allocate sliced VBI buffers if needed. */
|
/* First try to allocate sliced VBI buffers if needed. */
|
||||||
|
@ -235,7 +235,7 @@ int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||||
CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
|
CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
|
||||||
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
|
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
|
||||||
struct cx2341x_mpeg_params p = cx->params;
|
struct cx2341x_mpeg_params p = cx->params;
|
||||||
int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->capturing), arg, cmd);
|
int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), arg, cmd);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -295,7 +295,7 @@ int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
|
||||||
CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
|
CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
|
||||||
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
|
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
|
||||||
return cx2341x_ext_ctrls(&cx->params,
|
return cx2341x_ext_ctrls(&cx->params,
|
||||||
atomic_read(&cx->capturing), arg, cmd);
|
atomic_read(&cx->ana_capturing), arg, cmd);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -889,7 +889,7 @@ static void cx18_remove(struct pci_dev *pci_dev)
|
||||||
|
|
||||||
/* Stop all captures */
|
/* Stop all captures */
|
||||||
CX18_DEBUG_INFO("Stopping all streams\n");
|
CX18_DEBUG_INFO("Stopping all streams\n");
|
||||||
if (atomic_read(&cx->capturing) > 0)
|
if (atomic_read(&cx->tot_capturing) > 0)
|
||||||
cx18_stop_all_captures(cx);
|
cx18_stop_all_captures(cx);
|
||||||
|
|
||||||
/* Interrupts */
|
/* Interrupts */
|
||||||
|
|
|
@ -380,7 +380,8 @@ struct cx18 {
|
||||||
int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */
|
int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */
|
||||||
struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */
|
struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */
|
||||||
unsigned long i_flags; /* global cx18 flags */
|
unsigned long i_flags; /* global cx18 flags */
|
||||||
atomic_t capturing; /* count number of active capture streams */
|
atomic_t ana_capturing; /* count number of active analog capture streams */
|
||||||
|
atomic_t tot_capturing; /* total count number of active capture streams */
|
||||||
spinlock_t lock; /* lock access to this struct */
|
spinlock_t lock; /* lock access to this struct */
|
||||||
int search_pack_header;
|
int search_pack_header;
|
||||||
|
|
||||||
|
|
|
@ -318,7 +318,7 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
|
||||||
size_t tot_written = 0;
|
size_t tot_written = 0;
|
||||||
int single_frame = 0;
|
int single_frame = 0;
|
||||||
|
|
||||||
if (atomic_read(&cx->capturing) == 0 && s->id == -1) {
|
if (atomic_read(&cx->ana_capturing) == 0 && s->id == -1) {
|
||||||
/* shouldn't happen */
|
/* shouldn't happen */
|
||||||
CX18_DEBUG_WARN("Stream %s not initialized before read\n",
|
CX18_DEBUG_WARN("Stream %s not initialized before read\n",
|
||||||
s->name);
|
s->name);
|
||||||
|
@ -581,7 +581,7 @@ int cx18_v4l2_close(struct inode *inode, struct file *filp)
|
||||||
cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
|
cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
|
||||||
/* Select correct audio input (i.e. TV tuner or Line in) */
|
/* Select correct audio input (i.e. TV tuner or Line in) */
|
||||||
cx18_audio_set_io(cx);
|
cx18_audio_set_io(cx);
|
||||||
if (atomic_read(&cx->capturing) > 0) {
|
if (atomic_read(&cx->ana_capturing) > 0) {
|
||||||
/* Undo video mute */
|
/* Undo video mute */
|
||||||
cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
|
cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
|
||||||
cx->params.video_mute |
|
cx->params.video_mute |
|
||||||
|
@ -627,7 +627,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
|
if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
|
||||||
if (atomic_read(&cx->capturing) > 0) {
|
if (atomic_read(&cx->ana_capturing) > 0) {
|
||||||
/* switching to radio while capture is
|
/* switching to radio while capture is
|
||||||
in progress is not polite */
|
in progress is not polite */
|
||||||
cx18_release_stream(s);
|
cx18_release_stream(s);
|
||||||
|
@ -694,7 +694,7 @@ int cx18_v4l2_open(struct inode *inode, struct file *filp)
|
||||||
|
|
||||||
void cx18_mute(struct cx18 *cx)
|
void cx18_mute(struct cx18 *cx)
|
||||||
{
|
{
|
||||||
if (atomic_read(&cx->capturing))
|
if (atomic_read(&cx->ana_capturing))
|
||||||
cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
|
cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
|
||||||
cx18_find_handle(cx), 1);
|
cx18_find_handle(cx), 1);
|
||||||
CX18_DEBUG_INFO("Mute\n");
|
CX18_DEBUG_INFO("Mute\n");
|
||||||
|
@ -702,7 +702,7 @@ void cx18_mute(struct cx18 *cx)
|
||||||
|
|
||||||
void cx18_unmute(struct cx18 *cx)
|
void cx18_unmute(struct cx18 *cx)
|
||||||
{
|
{
|
||||||
if (atomic_read(&cx->capturing)) {
|
if (atomic_read(&cx->ana_capturing)) {
|
||||||
cx18_msleep_timeout(100, 0);
|
cx18_msleep_timeout(100, 0);
|
||||||
cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
|
cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
|
||||||
cx18_find_handle(cx), 12);
|
cx18_find_handle(cx), 12);
|
||||||
|
|
|
@ -247,7 +247,7 @@ static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
|
||||||
|
|
||||||
if (!set_fmt || (cx->params.width == w && cx->params.height == h))
|
if (!set_fmt || (cx->params.width == w && cx->params.height == h))
|
||||||
return 0;
|
return 0;
|
||||||
if (atomic_read(&cx->capturing) > 0)
|
if (atomic_read(&cx->ana_capturing) > 0)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
cx->params.width = w;
|
cx->params.width = w;
|
||||||
|
@ -264,7 +264,7 @@ static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
|
||||||
if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
|
if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
|
||||||
if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI &&
|
if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI &&
|
||||||
cx->vbi.sliced_in->service_set &&
|
cx->vbi.sliced_in->service_set &&
|
||||||
atomic_read(&cx->capturing) > 0)
|
atomic_read(&cx->ana_capturing) > 0)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
if (set_fmt) {
|
if (set_fmt) {
|
||||||
cx->vbi.sliced_in->service_set = 0;
|
cx->vbi.sliced_in->service_set = 0;
|
||||||
|
@ -293,7 +293,7 @@ static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
|
||||||
return 0;
|
return 0;
|
||||||
if (set == 0)
|
if (set == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (atomic_read(&cx->capturing) > 0 && cx->vbi.sliced_in->service_set == 0)
|
if (atomic_read(&cx->ana_capturing) > 0 && cx->vbi.sliced_in->service_set == 0)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
|
cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
|
||||||
memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
|
memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
|
||||||
|
@ -581,7 +581,7 @@ int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
|
if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
|
||||||
atomic_read(&cx->capturing) > 0) {
|
atomic_read(&cx->ana_capturing) > 0) {
|
||||||
/* Switching standard would turn off the radio or mess
|
/* Switching standard would turn off the radio or mess
|
||||||
with already running streams, prevent that by
|
with already running streams, prevent that by
|
||||||
returning EBUSY. */
|
returning EBUSY. */
|
||||||
|
@ -677,7 +677,7 @@ int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg
|
||||||
enc->flags = 0;
|
enc->flags = 0;
|
||||||
if (try)
|
if (try)
|
||||||
return 0;
|
return 0;
|
||||||
if (!atomic_read(&cx->capturing))
|
if (!atomic_read(&cx->ana_capturing))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
|
if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -689,7 +689,7 @@ int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg
|
||||||
enc->flags = 0;
|
enc->flags = 0;
|
||||||
if (try)
|
if (try)
|
||||||
return 0;
|
return 0;
|
||||||
if (!atomic_read(&cx->capturing))
|
if (!atomic_read(&cx->ana_capturing))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
|
if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -444,7 +444,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
|
||||||
s->handle = data[0];
|
s->handle = data[0];
|
||||||
cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
|
cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
|
||||||
|
|
||||||
if (atomic_read(&cx->capturing) == 0 && !ts) {
|
if (atomic_read(&cx->ana_capturing) == 0 && !ts) {
|
||||||
/* Stuff from Windows, we don't know what it is */
|
/* Stuff from Windows, we don't know what it is */
|
||||||
cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
|
cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
|
||||||
cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
|
cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
|
||||||
|
@ -467,7 +467,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
|
||||||
cx2341x_update(cx, cx18_api_func, NULL, &cx->params);
|
cx2341x_update(cx, cx18_api_func, NULL, &cx->params);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atomic_read(&cx->capturing) == 0) {
|
if (atomic_read(&cx->tot_capturing) == 0) {
|
||||||
clear_bit(CX18_F_I_EOS, &cx->i_flags);
|
clear_bit(CX18_F_I_EOS, &cx->i_flags);
|
||||||
write_reg(7, CX18_DSP0_INTERRUPT_MASK);
|
write_reg(7, CX18_DSP0_INTERRUPT_MASK);
|
||||||
}
|
}
|
||||||
|
@ -493,7 +493,9 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* you're live! sit back and await interrupts :) */
|
/* you're live! sit back and await interrupts :) */
|
||||||
atomic_inc(&cx->capturing);
|
if (!ts)
|
||||||
|
atomic_inc(&cx->ana_capturing);
|
||||||
|
atomic_inc(&cx->tot_capturing);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,7 +526,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
|
||||||
|
|
||||||
CX18_DEBUG_INFO("Stop Capture\n");
|
CX18_DEBUG_INFO("Stop Capture\n");
|
||||||
|
|
||||||
if (atomic_read(&cx->capturing) == 0)
|
if (atomic_read(&cx->tot_capturing) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (s->type == CX18_ENC_STREAM_TYPE_MPG)
|
if (s->type == CX18_ENC_STREAM_TYPE_MPG)
|
||||||
|
@ -538,7 +540,9 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
|
||||||
CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
|
CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_dec(&cx->capturing);
|
if (s->type != CX18_ENC_STREAM_TYPE_TS)
|
||||||
|
atomic_dec(&cx->ana_capturing);
|
||||||
|
atomic_dec(&cx->tot_capturing);
|
||||||
|
|
||||||
/* Clear capture and no-read bits */
|
/* Clear capture and no-read bits */
|
||||||
clear_bit(CX18_F_S_STREAMING, &s->s_flags);
|
clear_bit(CX18_F_S_STREAMING, &s->s_flags);
|
||||||
|
@ -546,7 +550,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
|
||||||
cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
|
cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
|
||||||
s->handle = 0xffffffff;
|
s->handle = 0xffffffff;
|
||||||
|
|
||||||
if (atomic_read(&cx->capturing) > 0)
|
if (atomic_read(&cx->tot_capturing) > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
write_reg(5, CX18_DSP0_INTERRUPT_MASK);
|
write_reg(5, CX18_DSP0_INTERRUPT_MASK);
|
||||||
|
|
Loading…
Reference in New Issue