Lines Matching +full:dual +full:- +full:radio

1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Derived from ivtv-fileops.c
11 #include "cx18-driver.h"
12 #include "cx18-fileops.h"
13 #include "cx18-i2c.h"
14 #include "cx18-queue.h"
15 #include "cx18-vbi.h"
16 #include "cx18-audio.h"
17 #include "cx18-mailbox.h"
18 #include "cx18-scb.h"
19 #include "cx18-streams.h"
20 #include "cx18-controls.h"
21 #include "cx18-ioctl.h"
22 #include "cx18-cards.h"
23 #include <media/v4l2-event.h>
28 Possible error returns: -EBUSY if someone else has claimed
32 struct cx18 *cx = id->cx; in cx18_claim_stream()
33 struct cx18_stream *s = &cx->streams[type]; in cx18_claim_stream()
39 return -EINVAL; in cx18_claim_stream()
42 if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) { in cx18_claim_stream()
44 if (s->id == id->open_id) { in cx18_claim_stream()
48 if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) { in cx18_claim_stream()
52 s->id = id->open_id; in cx18_claim_stream()
58 return -EBUSY; in cx18_claim_stream()
60 s->id = id->open_id; in cx18_claim_stream()
73 s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; in cx18_claim_stream()
74 if (cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) in cx18_claim_stream()
75 s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; in cx18_claim_stream()
79 set_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); in cx18_claim_stream()
82 set_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags); in cx18_claim_stream()
91 struct cx18 *cx = s->cx; in cx18_release_stream()
94 s->id = -1; in cx18_release_stream()
95 if (s->type == CX18_ENC_STREAM_TYPE_IDX) { in cx18_release_stream()
103 if (s->type == CX18_ENC_STREAM_TYPE_VBI && in cx18_release_stream()
104 test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) { in cx18_release_stream()
108 if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) { in cx18_release_stream()
109 CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name); in cx18_release_stream()
121 if (s->type != CX18_ENC_STREAM_TYPE_MPG) in cx18_release_stream()
125 s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; in cx18_release_stream()
126 if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) { in cx18_release_stream()
127 clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); in cx18_release_stream()
132 s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; in cx18_release_stream()
133 if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) { in cx18_release_stream()
134 if (s_assoc->id == -1) { in cx18_release_stream()
139 clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); in cx18_release_stream()
150 const u32 dual = 0x0200; in cx18_dualwatch() local
152 new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); in cx18_dualwatch()
157 new_stereo_mode = dual; in cx18_dualwatch()
159 if (new_stereo_mode == cx->dualwatch_stereo_mode) in cx18_dualwatch()
163 cx->dualwatch_stereo_mode, new_stereo_mode); in cx18_dualwatch()
164 if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode)) in cx18_dualwatch()
172 struct cx18 *cx = s->cx; in cx18_get_mdl()
173 struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; in cx18_get_mdl()
179 if (s->type == CX18_ENC_STREAM_TYPE_MPG) { in cx18_get_mdl()
181 if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) { in cx18_get_mdl()
182 cx->dualwatch_jiffies = jiffies; in cx18_get_mdl()
185 if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && in cx18_get_mdl()
186 !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { in cx18_get_mdl()
188 &s_vbi->q_full))) { in cx18_get_mdl()
191 s_vbi->type); in cx18_get_mdl()
195 mdl = &cx->vbi.sliced_mpeg_mdl; in cx18_get_mdl()
196 if (mdl->readpos != mdl->bytesused) in cx18_get_mdl()
201 mdl = cx18_dequeue(s, &s->q_full); in cx18_get_mdl()
204 &mdl->m_flags)) in cx18_get_mdl()
206 if (s->type == CX18_ENC_STREAM_TYPE_MPG) in cx18_get_mdl()
211 cx18_process_vbi_data(cx, mdl, s->type); in cx18_get_mdl()
217 if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) { in cx18_get_mdl()
218 CX18_DEBUG_INFO("EOS %s\n", s->name); in cx18_get_mdl()
224 *err = -EAGAIN; in cx18_get_mdl()
229 prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); in cx18_get_mdl()
232 if (!atomic_read(&s->q_full.depth)) in cx18_get_mdl()
234 finish_wait(&s->waitq, &wait); in cx18_get_mdl()
237 CX18_DEBUG_INFO("User stopped %s\n", s->name); in cx18_get_mdl()
238 *err = -EINTR; in cx18_get_mdl()
246 struct cx18_mdl *mdl = &cx->vbi.sliced_mpeg_mdl; in cx18_setup_sliced_vbi_mdl()
247 struct cx18_buffer *buf = &cx->vbi.sliced_mpeg_buf; in cx18_setup_sliced_vbi_mdl()
248 int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; in cx18_setup_sliced_vbi_mdl()
250 buf->buf = cx->vbi.sliced_mpeg_data[idx]; in cx18_setup_sliced_vbi_mdl()
251 buf->bytesused = cx->vbi.sliced_mpeg_size[idx]; in cx18_setup_sliced_vbi_mdl()
252 buf->readpos = 0; in cx18_setup_sliced_vbi_mdl()
254 mdl->curr_buf = NULL; in cx18_setup_sliced_vbi_mdl()
255 mdl->bytesused = cx->vbi.sliced_mpeg_size[idx]; in cx18_setup_sliced_vbi_mdl()
256 mdl->readpos = 0; in cx18_setup_sliced_vbi_mdl()
262 struct cx18 *cx = s->cx; in cx18_copy_buf_to_user()
263 size_t len = buf->bytesused - buf->readpos; in cx18_copy_buf_to_user()
268 if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && in cx18_copy_buf_to_user()
269 !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) { in cx18_copy_buf_to_user()
272 * an MPEG-2 Program Pack start code, and provide only in cx18_copy_buf_to_user()
276 * This will not work for an MPEG-2 TS and has only been in cx18_copy_buf_to_user()
277 * verified by analysis to work for an MPEG-2 PS. Helen Buus in cx18_copy_buf_to_user()
278 * pointed out this works for the CX23416 MPEG-2 DVD compatible in cx18_copy_buf_to_user()
280 * stream types use an MPEG-2 PS container. in cx18_copy_buf_to_user()
283 * An MPEG-2 Program Stream (PS) is a series of in cx18_copy_buf_to_user()
284 * MPEG-2 Program Packs terminated by an in cx18_copy_buf_to_user()
289 const char *start = buf->buf + buf->readpos; in cx18_copy_buf_to_user()
292 u8 ch = cx->search_pack_header ? 0xba : 0xe0; in cx18_copy_buf_to_user()
296 /* Scan for a 0 to find a potential MPEG-2 start code */ in cx18_copy_buf_to_user()
297 q = memchr(p, 0, start + len - p); in cx18_copy_buf_to_user()
303 * MPEG-2 Pack header start code: 0x00 0x00 0x01 0xba in cx18_copy_buf_to_user()
304 * or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0 in cx18_copy_buf_to_user()
306 if ((char *)q + 15 >= buf->buf + buf->bytesused || in cx18_copy_buf_to_user()
311 if (!cx->search_pack_header) { in cx18_copy_buf_to_user()
322 cx->search_pack_header = 1; in cx18_copy_buf_to_user()
343 cx->search_pack_header = 0; /* expect vid PES */ in cx18_copy_buf_to_user()
344 len = (char *)q - start; in cx18_copy_buf_to_user()
351 if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { in cx18_copy_buf_to_user()
353 len, s->name); in cx18_copy_buf_to_user()
354 return -EFAULT; in cx18_copy_buf_to_user()
356 buf->readpos += len; in cx18_copy_buf_to_user()
357 if (s->type == CX18_ENC_STREAM_TYPE_MPG && in cx18_copy_buf_to_user()
358 buf != &cx->vbi.sliced_mpeg_buf) in cx18_copy_buf_to_user()
359 cx->mpg_data_received += len; in cx18_copy_buf_to_user()
370 if (mdl->curr_buf == NULL) in cx18_copy_mdl_to_user()
371 mdl->curr_buf = list_first_entry(&mdl->buf_list, in cx18_copy_mdl_to_user()
374 if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { in cx18_copy_mdl_to_user()
380 mdl->readpos = mdl->bytesused; in cx18_copy_mdl_to_user()
384 list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) { in cx18_copy_mdl_to_user()
386 if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused) in cx18_copy_mdl_to_user()
389 rc = cx18_copy_buf_to_user(s, mdl->curr_buf, ubuf + tot_written, in cx18_copy_mdl_to_user()
390 ucount - tot_written, &stop); in cx18_copy_mdl_to_user()
393 mdl->readpos += rc; in cx18_copy_mdl_to_user()
398 mdl->curr_buf->readpos < mdl->curr_buf->bytesused || in cx18_copy_mdl_to_user()
399 mdl->readpos >= mdl->bytesused) /* MDL buffers drained */ in cx18_copy_mdl_to_user()
408 struct cx18 *cx = s->cx; in cx18_read()
412 if (atomic_read(&cx->ana_capturing) == 0 && s->id == -1) { in cx18_read()
415 s->name); in cx18_read()
416 return -EIO; in cx18_read()
420 frames should arrive one-by-one, so make sure we never output more in cx18_read()
422 if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx)) in cx18_read()
437 clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); in cx18_read()
438 clear_bit(CX18_F_S_APPL_IO, &s->s_flags); in cx18_read()
446 tot_count - tot_written); in cx18_read()
448 if (mdl != &cx->vbi.sliced_mpeg_mdl) { in cx18_read()
449 if (mdl->readpos == mdl->bytesused) in cx18_read()
452 cx18_push(s, mdl, &s->q_full); in cx18_read()
453 } else if (mdl->readpos == mdl->bytesused) { in cx18_read()
454 int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; in cx18_read()
456 cx->vbi.sliced_mpeg_size[idx] = 0; in cx18_read()
457 cx->vbi.inserted_frame++; in cx18_read()
458 cx->vbi_data_inserted += mdl->bytesused; in cx18_read()
474 struct cx18 *cx = s->cx; in cx18_read_pos()
476 CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); in cx18_read_pos()
484 struct cx18 *cx = id->cx; in cx18_start_capture()
485 struct cx18_stream *s = &cx->streams[id->type]; in cx18_start_capture()
489 if (s->type == CX18_ENC_STREAM_TYPE_RAD) { in cx18_start_capture()
491 return -EPERM; in cx18_start_capture()
495 if (cx18_claim_stream(id, s->type)) in cx18_start_capture()
496 return -EBUSY; in cx18_start_capture()
500 if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || in cx18_start_capture()
501 test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { in cx18_start_capture()
502 set_bit(CX18_F_S_APPL_IO, &s->s_flags); in cx18_start_capture()
507 s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; in cx18_start_capture()
508 s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; in cx18_start_capture()
509 if (s->type == CX18_ENC_STREAM_TYPE_MPG) { in cx18_start_capture()
515 if (test_bit(CX18_F_S_INTERNAL_USE, &s_idx->s_flags) && in cx18_start_capture()
516 !test_and_set_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { in cx18_start_capture()
519 clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags); in cx18_start_capture()
524 if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && in cx18_start_capture()
525 !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { in cx18_start_capture()
528 clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); in cx18_start_capture()
538 set_bit(CX18_F_S_APPL_IO, &s->s_flags); in cx18_start_capture()
540 if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) in cx18_start_capture()
541 cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle); in cx18_start_capture()
546 CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); in cx18_start_capture()
553 if (s->type == CX18_ENC_STREAM_TYPE_MPG) { in cx18_start_capture()
555 if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { in cx18_start_capture()
557 clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags); in cx18_start_capture()
560 if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && in cx18_start_capture()
561 !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { in cx18_start_capture()
563 clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); in cx18_start_capture()
566 clear_bit(CX18_F_S_STREAMING, &s->s_flags); in cx18_start_capture()
568 return -EIO; in cx18_start_capture()
575 struct cx18 *cx = id->cx; in cx18_v4l2_read()
576 struct cx18_stream *s = &cx->streams[id->type]; in cx18_v4l2_read()
579 CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); in cx18_v4l2_read()
581 mutex_lock(&cx->serialize_lock); in cx18_v4l2_read()
583 mutex_unlock(&cx->serialize_lock); in cx18_v4l2_read()
587 return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); in cx18_v4l2_read()
594 struct cx18 *cx = id->cx; in cx18_v4l2_enc_poll()
595 struct cx18_stream *s = &cx->streams[id->type]; in cx18_v4l2_enc_poll()
596 int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); in cx18_v4l2_enc_poll()
600 if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags) && in cx18_v4l2_enc_poll()
604 mutex_lock(&cx->serialize_lock); in cx18_v4l2_enc_poll()
606 mutex_unlock(&cx->serialize_lock); in cx18_v4l2_enc_poll()
609 s->name, rc); in cx18_v4l2_enc_poll()
617 if (v4l2_event_pending(&id->fh)) in cx18_v4l2_enc_poll()
620 poll_wait(filp, &s->waitq, wait); in cx18_v4l2_enc_poll()
622 if (atomic_read(&s->q_full.depth)) in cx18_v4l2_enc_poll()
642 struct cx18 *cx = s->cx; in cx18_stop_capture()
643 struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; in cx18_stop_capture()
644 struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; in cx18_stop_capture()
646 CX18_DEBUG_IOCTL("close() of %s\n", s->name); in cx18_stop_capture()
651 if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) { in cx18_stop_capture()
653 if (s->type == CX18_ENC_STREAM_TYPE_MPG) { in cx18_stop_capture()
655 if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && in cx18_stop_capture()
656 !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { in cx18_stop_capture()
660 if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { in cx18_stop_capture()
665 if (s->type == CX18_ENC_STREAM_TYPE_VBI && in cx18_stop_capture()
666 test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) in cx18_stop_capture()
668 s->id = -1; in cx18_stop_capture()
673 clear_bit(CX18_F_S_APPL_IO, &s->s_flags); in cx18_stop_capture()
674 clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); in cx18_stop_capture()
681 struct v4l2_fh *fh = filp->private_data; in cx18_v4l2_close()
683 struct cx18 *cx = id->cx; in cx18_v4l2_close()
684 struct cx18_stream *s = &cx->streams[id->type]; in cx18_v4l2_close()
685 struct video_device *vdev = &s->video_dev; in cx18_v4l2_close()
687 CX18_DEBUG_IOCTL("close() of %s\n", s->name); in cx18_v4l2_close()
689 mutex_lock(&cx->serialize_lock); in cx18_v4l2_close()
690 /* Stop radio */ in cx18_v4l2_close()
691 if (id->type == CX18_ENC_STREAM_TYPE_RAD && in cx18_v4l2_close()
693 /* Closing radio device, return to TV mode */ in cx18_v4l2_close()
695 /* Mark that the radio is no longer in use */ in cx18_v4l2_close()
696 clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags); in cx18_v4l2_close()
698 cx18_call_all(cx, video, s_std, cx->std); in cx18_v4l2_close()
701 if (atomic_read(&cx->ana_capturing) > 0) { in cx18_v4l2_close()
703 cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, in cx18_v4l2_close()
704 (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) | in cx18_v4l2_close()
705 (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8))); in cx18_v4l2_close()
711 if (id->type == CX18_ENC_STREAM_TYPE_YUV && in cx18_v4l2_close()
712 filp->private_data == vdev->queue->owner) { in cx18_v4l2_close()
713 vb2_queue_release(vdev->queue); in cx18_v4l2_close()
714 vdev->queue->owner = NULL; in cx18_v4l2_close()
720 if (id->type != CX18_ENC_STREAM_TYPE_YUV && s->id == id->open_id) in cx18_v4l2_close()
723 mutex_unlock(&cx->serialize_lock); in cx18_v4l2_close()
729 struct cx18 *cx = s->cx; in cx18_serialized_open()
732 CX18_DEBUG_FILE("open %s\n", s->name); in cx18_serialized_open()
738 return -ENOMEM; in cx18_serialized_open()
740 v4l2_fh_init(&item->fh, &s->video_dev); in cx18_serialized_open()
742 item->cx = cx; in cx18_serialized_open()
743 item->type = s->type; in cx18_serialized_open()
745 item->open_id = cx->open_id++; in cx18_serialized_open()
746 filp->private_data = &item->fh; in cx18_serialized_open()
747 v4l2_fh_add(&item->fh); in cx18_serialized_open()
749 if (item->type == CX18_ENC_STREAM_TYPE_RAD && in cx18_serialized_open()
751 if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { in cx18_serialized_open()
752 if (atomic_read(&cx->ana_capturing) > 0) { in cx18_serialized_open()
753 /* switching to radio while capture is in cx18_serialized_open()
755 v4l2_fh_del(&item->fh); in cx18_serialized_open()
756 v4l2_fh_exit(&item->fh); in cx18_serialized_open()
758 return -EBUSY; in cx18_serialized_open()
762 /* Mark that the radio is being used. */ in cx18_serialized_open()
763 set_bit(CX18_F_I_RADIO_USER, &cx->i_flags); in cx18_serialized_open()
764 /* We have the radio */ in cx18_serialized_open()
766 /* Switch tuner to radio */ in cx18_serialized_open()
768 /* Select the correct audio input (i.e. radio tuner) */ in cx18_serialized_open()
781 struct cx18 *cx = s->cx; in cx18_v4l2_open()
783 mutex_lock(&cx->serialize_lock); in cx18_v4l2_open()
787 mutex_unlock(&cx->serialize_lock); in cx18_v4l2_open()
788 return -ENXIO; in cx18_v4l2_open()
791 mutex_unlock(&cx->serialize_lock); in cx18_v4l2_open()
798 if (atomic_read(&cx->ana_capturing)) { in cx18_mute()
811 if (atomic_read(&cx->ana_capturing)) { in cx18_unmute()