diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2008-05-25 10:21:27 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-06-05 05:35:45 -0400 |
commit | 31554ae599a8ff6854bf8ecbedc1946c64854388 (patch) | |
tree | 33169d397f17069e72d72695f6adb59a4a25b210 | |
parent | be303e16dbd210077c697aaf2f0960413166b53d (diff) |
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>
-rw-r--r-- | drivers/media/video/cx18/cx18-controls.c | 6 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.h | 3 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-fileops.c | 10 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.c | 12 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.c | 16 |
6 files changed, 27 insertions, 22 deletions
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c index 2bdac5ebbb0d..87cf41021665 100644 --- a/drivers/media/video/cx18/cx18-controls.c +++ b/drivers/media/video/cx18/cx18-controls.c | |||
@@ -159,7 +159,7 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt | |||
159 | { | 159 | { |
160 | if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) | 160 | if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) |
161 | return -EINVAL; | 161 | return -EINVAL; |
162 | if (atomic_read(&cx->capturing) > 0) | 162 | if (atomic_read(&cx->ana_capturing) > 0) |
163 | return -EBUSY; | 163 | return -EBUSY; |
164 | 164 | ||
165 | /* First try to allocate sliced VBI buffers if needed. */ | 165 | /* 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) | |||
235 | CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); | 235 | CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); |
236 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | 236 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { |
237 | struct cx2341x_mpeg_params p = cx->params; | 237 | struct cx2341x_mpeg_params p = cx->params; |
238 | int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->capturing), arg, cmd); | 238 | int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), arg, cmd); |
239 | 239 | ||
240 | if (err) | 240 | if (err) |
241 | return err; | 241 | return err; |
@@ -295,7 +295,7 @@ int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg) | |||
295 | CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); | 295 | CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); |
296 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | 296 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) |
297 | return cx2341x_ext_ctrls(&cx->params, | 297 | return cx2341x_ext_ctrls(&cx->params, |
298 | atomic_read(&cx->capturing), arg, cmd); | 298 | atomic_read(&cx->ana_capturing), arg, cmd); |
299 | return -EINVAL; | 299 | return -EINVAL; |
300 | } | 300 | } |
301 | 301 | ||
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 0dd4e0529970..472f88e64199 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -889,7 +889,7 @@ static void cx18_remove(struct pci_dev *pci_dev) | |||
889 | 889 | ||
890 | /* Stop all captures */ | 890 | /* Stop all captures */ |
891 | CX18_DEBUG_INFO("Stopping all streams\n"); | 891 | CX18_DEBUG_INFO("Stopping all streams\n"); |
892 | if (atomic_read(&cx->capturing) > 0) | 892 | if (atomic_read(&cx->tot_capturing) > 0) |
893 | cx18_stop_all_captures(cx); | 893 | cx18_stop_all_captures(cx); |
894 | 894 | ||
895 | /* Interrupts */ | 895 | /* Interrupts */ |
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index a2a6c58d12fe..9c6a53477a1b 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h | |||
@@ -380,7 +380,8 @@ struct cx18 { | |||
380 | int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */ | 380 | int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */ |
381 | struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */ | 381 | struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */ |
382 | unsigned long i_flags; /* global cx18 flags */ | 382 | unsigned long i_flags; /* global cx18 flags */ |
383 | atomic_t capturing; /* count number of active capture streams */ | 383 | atomic_t ana_capturing; /* count number of active analog capture streams */ |
384 | atomic_t tot_capturing; /* total count number of active capture streams */ | ||
384 | spinlock_t lock; /* lock access to this struct */ | 385 | spinlock_t lock; /* lock access to this struct */ |
385 | int search_pack_header; | 386 | int search_pack_header; |
386 | 387 | ||
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 0b3141db174b..d0d7888f269a 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c | |||
@@ -318,7 +318,7 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, | |||
318 | size_t tot_written = 0; | 318 | size_t tot_written = 0; |
319 | int single_frame = 0; | 319 | int single_frame = 0; |
320 | 320 | ||
321 | if (atomic_read(&cx->capturing) == 0 && s->id == -1) { | 321 | if (atomic_read(&cx->ana_capturing) == 0 && s->id == -1) { |
322 | /* shouldn't happen */ | 322 | /* shouldn't happen */ |
323 | CX18_DEBUG_WARN("Stream %s not initialized before read\n", | 323 | CX18_DEBUG_WARN("Stream %s not initialized before read\n", |
324 | s->name); | 324 | s->name); |
@@ -581,7 +581,7 @@ int cx18_v4l2_close(struct inode *inode, struct file *filp) | |||
581 | cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); | 581 | cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); |
582 | /* Select correct audio input (i.e. TV tuner or Line in) */ | 582 | /* Select correct audio input (i.e. TV tuner or Line in) */ |
583 | cx18_audio_set_io(cx); | 583 | cx18_audio_set_io(cx); |
584 | if (atomic_read(&cx->capturing) > 0) { | 584 | if (atomic_read(&cx->ana_capturing) > 0) { |
585 | /* Undo video mute */ | 585 | /* Undo video mute */ |
586 | cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, | 586 | cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, |
587 | cx->params.video_mute | | 587 | cx->params.video_mute | |
@@ -627,7 +627,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) | |||
627 | } | 627 | } |
628 | 628 | ||
629 | if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { | 629 | if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { |
630 | if (atomic_read(&cx->capturing) > 0) { | 630 | if (atomic_read(&cx->ana_capturing) > 0) { |
631 | /* switching to radio while capture is | 631 | /* switching to radio while capture is |
632 | in progress is not polite */ | 632 | in progress is not polite */ |
633 | cx18_release_stream(s); | 633 | cx18_release_stream(s); |
@@ -694,7 +694,7 @@ int cx18_v4l2_open(struct inode *inode, struct file *filp) | |||
694 | 694 | ||
695 | void cx18_mute(struct cx18 *cx) | 695 | void cx18_mute(struct cx18 *cx) |
696 | { | 696 | { |
697 | if (atomic_read(&cx->capturing)) | 697 | if (atomic_read(&cx->ana_capturing)) |
698 | cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, | 698 | cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, |
699 | cx18_find_handle(cx), 1); | 699 | cx18_find_handle(cx), 1); |
700 | CX18_DEBUG_INFO("Mute\n"); | 700 | CX18_DEBUG_INFO("Mute\n"); |
@@ -702,7 +702,7 @@ void cx18_mute(struct cx18 *cx) | |||
702 | 702 | ||
703 | void cx18_unmute(struct cx18 *cx) | 703 | void cx18_unmute(struct cx18 *cx) |
704 | { | 704 | { |
705 | if (atomic_read(&cx->capturing)) { | 705 | if (atomic_read(&cx->ana_capturing)) { |
706 | cx18_msleep_timeout(100, 0); | 706 | cx18_msleep_timeout(100, 0); |
707 | cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, | 707 | cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, |
708 | cx18_find_handle(cx), 12); | 708 | cx18_find_handle(cx), 12); |
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index dbdcb86ec5aa..4151f1e5493f 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c | |||
@@ -247,7 +247,7 @@ static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype, | |||
247 | 247 | ||
248 | if (!set_fmt || (cx->params.width == w && cx->params.height == h)) | 248 | if (!set_fmt || (cx->params.width == w && cx->params.height == h)) |
249 | return 0; | 249 | return 0; |
250 | if (atomic_read(&cx->capturing) > 0) | 250 | if (atomic_read(&cx->ana_capturing) > 0) |
251 | return -EBUSY; | 251 | return -EBUSY; |
252 | 252 | ||
253 | cx->params.width = w; | 253 | cx->params.width = w; |
@@ -264,7 +264,7 @@ static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype, | |||
264 | if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | 264 | if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { |
265 | if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI && | 265 | if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI && |
266 | cx->vbi.sliced_in->service_set && | 266 | cx->vbi.sliced_in->service_set && |
267 | atomic_read(&cx->capturing) > 0) | 267 | atomic_read(&cx->ana_capturing) > 0) |
268 | return -EBUSY; | 268 | return -EBUSY; |
269 | if (set_fmt) { | 269 | if (set_fmt) { |
270 | cx->vbi.sliced_in->service_set = 0; | 270 | cx->vbi.sliced_in->service_set = 0; |
@@ -293,7 +293,7 @@ static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype, | |||
293 | return 0; | 293 | return 0; |
294 | if (set == 0) | 294 | if (set == 0) |
295 | return -EINVAL; | 295 | return -EINVAL; |
296 | if (atomic_read(&cx->capturing) > 0 && cx->vbi.sliced_in->service_set == 0) | 296 | if (atomic_read(&cx->ana_capturing) > 0 && cx->vbi.sliced_in->service_set == 0) |
297 | return -EBUSY; | 297 | return -EBUSY; |
298 | cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); | 298 | cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); |
299 | memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in)); | 299 | 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 | |||
581 | break; | 581 | break; |
582 | 582 | ||
583 | if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || | 583 | if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || |
584 | atomic_read(&cx->capturing) > 0) { | 584 | atomic_read(&cx->ana_capturing) > 0) { |
585 | /* Switching standard would turn off the radio or mess | 585 | /* Switching standard would turn off the radio or mess |
586 | with already running streams, prevent that by | 586 | with already running streams, prevent that by |
587 | returning EBUSY. */ | 587 | returning EBUSY. */ |
@@ -677,7 +677,7 @@ int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg | |||
677 | enc->flags = 0; | 677 | enc->flags = 0; |
678 | if (try) | 678 | if (try) |
679 | return 0; | 679 | return 0; |
680 | if (!atomic_read(&cx->capturing)) | 680 | if (!atomic_read(&cx->ana_capturing)) |
681 | return -EPERM; | 681 | return -EPERM; |
682 | if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) | 682 | if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) |
683 | return 0; | 683 | return 0; |
@@ -689,7 +689,7 @@ int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg | |||
689 | enc->flags = 0; | 689 | enc->flags = 0; |
690 | if (try) | 690 | if (try) |
691 | return 0; | 691 | return 0; |
692 | if (!atomic_read(&cx->capturing)) | 692 | if (!atomic_read(&cx->ana_capturing)) |
693 | return -EPERM; | 693 | return -EPERM; |
694 | if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) | 694 | if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) |
695 | return 0; | 695 | return 0; |
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index dee6cc988090..5a065869401c 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c | |||
@@ -444,7 +444,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | |||
444 | s->handle = data[0]; | 444 | s->handle = data[0]; |
445 | cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); | 445 | cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); |
446 | 446 | ||
447 | if (atomic_read(&cx->capturing) == 0 && !ts) { | 447 | if (atomic_read(&cx->ana_capturing) == 0 && !ts) { |
448 | /* Stuff from Windows, we don't know what it is */ | 448 | /* Stuff from Windows, we don't know what it is */ |
449 | cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0); | 449 | cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0); |
450 | cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1); | 450 | 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) | |||
467 | cx2341x_update(cx, cx18_api_func, NULL, &cx->params); | 467 | cx2341x_update(cx, cx18_api_func, NULL, &cx->params); |
468 | } | 468 | } |
469 | 469 | ||
470 | if (atomic_read(&cx->capturing) == 0) { | 470 | if (atomic_read(&cx->tot_capturing) == 0) { |
471 | clear_bit(CX18_F_I_EOS, &cx->i_flags); | 471 | clear_bit(CX18_F_I_EOS, &cx->i_flags); |
472 | write_reg(7, CX18_DSP0_INTERRUPT_MASK); | 472 | write_reg(7, CX18_DSP0_INTERRUPT_MASK); |
473 | } | 473 | } |
@@ -493,7 +493,9 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | |||
493 | } | 493 | } |
494 | 494 | ||
495 | /* you're live! sit back and await interrupts :) */ | 495 | /* you're live! sit back and await interrupts :) */ |
496 | atomic_inc(&cx->capturing); | 496 | if (!ts) |
497 | atomic_inc(&cx->ana_capturing); | ||
498 | atomic_inc(&cx->tot_capturing); | ||
497 | return 0; | 499 | return 0; |
498 | } | 500 | } |
499 | 501 | ||
@@ -524,7 +526,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) | |||
524 | 526 | ||
525 | CX18_DEBUG_INFO("Stop Capture\n"); | 527 | CX18_DEBUG_INFO("Stop Capture\n"); |
526 | 528 | ||
527 | if (atomic_read(&cx->capturing) == 0) | 529 | if (atomic_read(&cx->tot_capturing) == 0) |
528 | return 0; | 530 | return 0; |
529 | 531 | ||
530 | if (s->type == CX18_ENC_STREAM_TYPE_MPG) | 532 | 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) | |||
538 | CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n"); | 540 | CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n"); |
539 | } | 541 | } |
540 | 542 | ||
541 | atomic_dec(&cx->capturing); | 543 | if (s->type != CX18_ENC_STREAM_TYPE_TS) |
544 | atomic_dec(&cx->ana_capturing); | ||
545 | atomic_dec(&cx->tot_capturing); | ||
542 | 546 | ||
543 | /* Clear capture and no-read bits */ | 547 | /* Clear capture and no-read bits */ |
544 | clear_bit(CX18_F_S_STREAMING, &s->s_flags); | 548 | 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) | |||
546 | cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); | 550 | cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); |
547 | s->handle = 0xffffffff; | 551 | s->handle = 0xffffffff; |
548 | 552 | ||
549 | if (atomic_read(&cx->capturing) > 0) | 553 | if (atomic_read(&cx->tot_capturing) > 0) |
550 | return 0; | 554 | return 0; |
551 | 555 | ||
552 | write_reg(5, CX18_DSP0_INTERRUPT_MASK); | 556 | write_reg(5, CX18_DSP0_INTERRUPT_MASK); |