aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18/cx18-fileops.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx18/cx18-fileops.c')
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c205
1 files changed, 123 insertions, 82 deletions
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index c0885c69fd89..863ce7758239 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -37,15 +37,21 @@
37 37
38/* This function tries to claim the stream for a specific file descriptor. 38/* This function tries to claim the stream for a specific file descriptor.
39 If no one else is using this stream then the stream is claimed and 39 If no one else is using this stream then the stream is claimed and
40 associated VBI streams are also automatically claimed. 40 associated VBI and IDX streams are also automatically claimed.
41 Possible error returns: -EBUSY if someone else has claimed 41 Possible error returns: -EBUSY if someone else has claimed
42 the stream or 0 on success. */ 42 the stream or 0 on success. */
43static int cx18_claim_stream(struct cx18_open_id *id, int type) 43int cx18_claim_stream(struct cx18_open_id *id, int type)
44{ 44{
45 struct cx18 *cx = id->cx; 45 struct cx18 *cx = id->cx;
46 struct cx18_stream *s = &cx->streams[type]; 46 struct cx18_stream *s = &cx->streams[type];
47 struct cx18_stream *s_vbi; 47 struct cx18_stream *s_assoc;
48 int vbi_type; 48
49 /* Nothing should ever try to directly claim the IDX stream */
50 if (type == CX18_ENC_STREAM_TYPE_IDX) {
51 CX18_WARN("MPEG Index stream cannot be claimed "
52 "directly, but something tried.\n");
53 return -EINVAL;
54 }
49 55
50 if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) { 56 if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
51 /* someone already claimed this stream */ 57 /* someone already claimed this stream */
@@ -67,32 +73,47 @@ static int cx18_claim_stream(struct cx18_open_id *id, int type)
67 } 73 }
68 s->id = id->open_id; 74 s->id = id->open_id;
69 75
70 /* CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI 76 /*
71 (provided VBI insertion is on and sliced VBI is selected), for all 77 * CX18_ENC_STREAM_TYPE_MPG needs to claim:
72 other streams we're done */ 78 * CX18_ENC_STREAM_TYPE_VBI, if VBI insertion is on for sliced VBI, or
73 if (type == CX18_ENC_STREAM_TYPE_MPG && 79 * CX18_ENC_STREAM_TYPE_IDX, if VBI insertion is off for sliced VBI
74 cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) { 80 * (We don't yet fix up MPEG Index entries for our inserted packets).
75 vbi_type = CX18_ENC_STREAM_TYPE_VBI; 81 *
76 } else { 82 * For all other streams we're done.
83 */
84 if (type != CX18_ENC_STREAM_TYPE_MPG)
77 return 0; 85 return 0;
78 }
79 s_vbi = &cx->streams[vbi_type];
80 86
81 set_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags); 87 s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
88 if (cx->vbi.insert_mpeg && !cx18_raw_vbi(cx))
89 s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
90 else if (!cx18_stream_enabled(s_assoc))
91 return 0;
92
93 set_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);
82 94
83 /* mark that it is used internally */ 95 /* mark that it is used internally */
84 set_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags); 96 set_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags);
85 return 0; 97 return 0;
86} 98}
99EXPORT_SYMBOL(cx18_claim_stream);
87 100
88/* This function releases a previously claimed stream. It will take into 101/* This function releases a previously claimed stream. It will take into
89 account associated VBI streams. */ 102 account associated VBI streams. */
90static void cx18_release_stream(struct cx18_stream *s) 103void cx18_release_stream(struct cx18_stream *s)
91{ 104{
92 struct cx18 *cx = s->cx; 105 struct cx18 *cx = s->cx;
93 struct cx18_stream *s_vbi; 106 struct cx18_stream *s_assoc;
94 107
95 s->id = -1; 108 s->id = -1;
109 if (s->type == CX18_ENC_STREAM_TYPE_IDX) {
110 /*
111 * The IDX stream is only used internally, and can
112 * only be indirectly unclaimed by unclaiming the MPG stream.
113 */
114 return;
115 }
116
96 if (s->type == CX18_ENC_STREAM_TYPE_VBI && 117 if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
97 test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) { 118 test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) {
98 /* this stream is still in use internally */ 119 /* this stream is still in use internally */
@@ -105,25 +126,36 @@ static void cx18_release_stream(struct cx18_stream *s)
105 126
106 cx18_flush_queues(s); 127 cx18_flush_queues(s);
107 128
108 /* CX18_ENC_STREAM_TYPE_MPG needs to release CX18_ENC_STREAM_TYPE_VBI, 129 /*
109 for all other streams we're done */ 130 * CX18_ENC_STREAM_TYPE_MPG needs to release the
110 if (s->type == CX18_ENC_STREAM_TYPE_MPG) 131 * CX18_ENC_STREAM_TYPE_VBI and/or CX18_ENC_STREAM_TYPE_IDX streams.
111 s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; 132 *
112 else 133 * For all other streams we're done.
134 */
135 if (s->type != CX18_ENC_STREAM_TYPE_MPG)
113 return; 136 return;
114 137
115 /* clear internal use flag */ 138 /* Unclaim the associated MPEG Index stream */
116 if (!test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags)) { 139 s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
117 /* was already cleared */ 140 if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) {
118 return; 141 clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);
142 cx18_flush_queues(s_assoc);
119 } 143 }
120 if (s_vbi->id != -1) { 144
121 /* VBI stream still claimed by a file descriptor */ 145 /* Unclaim the associated VBI stream */
122 return; 146 s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
147 if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) {
148 if (s_assoc->id == -1) {
149 /*
150 * The VBI stream is not still claimed by a file
151 * descriptor, so completely unclaim it.
152 */
153 clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);
154 cx18_flush_queues(s_assoc);
155 }
123 } 156 }
124 clear_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags);
125 cx18_flush_queues(s_vbi);
126} 157}
158EXPORT_SYMBOL(cx18_release_stream);
127 159
128static void cx18_dualwatch(struct cx18 *cx) 160static void cx18_dualwatch(struct cx18 *cx)
129{ 161{
@@ -177,9 +209,7 @@ static struct cx18_mdl *cx18_get_mdl(struct cx18_stream *s, int non_block,
177 *err = 0; 209 *err = 0;
178 while (1) { 210 while (1) {
179 if (s->type == CX18_ENC_STREAM_TYPE_MPG) { 211 if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
180 /* Process pending program info updates and pending 212 /* Process pending program updates and VBI data */
181 VBI data */
182
183 if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) { 213 if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) {
184 cx->dualwatch_jiffies = jiffies; 214 cx->dualwatch_jiffies = jiffies;
185 cx18_dualwatch(cx); 215 cx18_dualwatch(cx);
@@ -362,18 +392,6 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
362 return len; 392 return len;
363} 393}
364 394
365/**
366 * list_entry_is_past_end - check if a previous loop cursor is off list end
367 * @pos: the type * previously used as a loop cursor.
368 * @head: the head for your list.
369 * @member: the name of the list_struct within the struct.
370 *
371 * Check if the entry's list_head is the head of the list, thus it's not a
372 * real entry but was the loop cursor that walked past the end
373 */
374#define list_entry_is_past_end(pos, head, member) \
375 (&pos->member == (head))
376
377static size_t cx18_copy_mdl_to_user(struct cx18_stream *s, 395static size_t cx18_copy_mdl_to_user(struct cx18_stream *s,
378 struct cx18_mdl *mdl, char __user *ubuf, size_t ucount) 396 struct cx18_mdl *mdl, char __user *ubuf, size_t ucount)
379{ 397{
@@ -498,6 +516,7 @@ int cx18_start_capture(struct cx18_open_id *id)
498 struct cx18 *cx = id->cx; 516 struct cx18 *cx = id->cx;
499 struct cx18_stream *s = &cx->streams[id->type]; 517 struct cx18_stream *s = &cx->streams[id->type];
500 struct cx18_stream *s_vbi; 518 struct cx18_stream *s_vbi;
519 struct cx18_stream *s_idx;
501 520
502 if (s->type == CX18_ENC_STREAM_TYPE_RAD) { 521 if (s->type == CX18_ENC_STREAM_TYPE_RAD) {
503 /* you cannot read from these stream types. */ 522 /* you cannot read from these stream types. */
@@ -516,25 +535,33 @@ int cx18_start_capture(struct cx18_open_id *id)
516 return 0; 535 return 0;
517 } 536 }
518 537
519 /* Start VBI capture if required */ 538 /* Start associated VBI or IDX stream capture if required */
520 s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; 539 s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
521 if (s->type == CX18_ENC_STREAM_TYPE_MPG && 540 s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
522 test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && 541 if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
523 !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { 542 /*
524 /* Note: the CX18_ENC_STREAM_TYPE_VBI is claimed 543 * The VBI and IDX streams should have been claimed
525 automatically when the MPG stream is claimed. 544 * automatically, if for internal use, when the MPG stream was
526 We only need to start the VBI capturing. */ 545 * claimed. We only need to start these streams capturing.
527 if (cx18_start_v4l2_encode_stream(s_vbi)) { 546 */
528 CX18_DEBUG_WARN("VBI capture start failed\n"); 547 if (test_bit(CX18_F_S_INTERNAL_USE, &s_idx->s_flags) &&
529 548 !test_and_set_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) {
530 /* Failure, clean up and return an error */ 549 if (cx18_start_v4l2_encode_stream(s_idx)) {
531 clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); 550 CX18_DEBUG_WARN("IDX capture start failed\n");
532 clear_bit(CX18_F_S_STREAMING, &s->s_flags); 551 clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags);
533 /* also releases the associated VBI stream */ 552 goto start_failed;
534 cx18_release_stream(s); 553 }
535 return -EIO; 554 CX18_DEBUG_INFO("IDX capture started\n");
555 }
556 if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
557 !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
558 if (cx18_start_v4l2_encode_stream(s_vbi)) {
559 CX18_DEBUG_WARN("VBI capture start failed\n");
560 clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
561 goto start_failed;
562 }
563 CX18_DEBUG_INFO("VBI insertion started\n");
536 } 564 }
537 CX18_DEBUG_INFO("VBI insertion started\n");
538 } 565 }
539 566
540 /* Tell the card to start capturing */ 567 /* Tell the card to start capturing */
@@ -547,19 +574,29 @@ int cx18_start_capture(struct cx18_open_id *id)
547 return 0; 574 return 0;
548 } 575 }
549 576
550 /* failure, clean up */ 577start_failed:
551 CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); 578 CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);
552 579
553 /* Note: the CX18_ENC_STREAM_TYPE_VBI is released 580 /*
554 automatically when the MPG stream is released. 581 * The associated VBI and IDX streams for internal use are released
555 We only need to stop the VBI capturing. */ 582 * automatically when the MPG stream is released. We only need to stop
556 if (s->type == CX18_ENC_STREAM_TYPE_MPG && 583 * the associated stream.
557 test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { 584 */
558 cx18_stop_v4l2_encode_stream(s_vbi, 0); 585 if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
559 clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); 586 /* Stop the IDX stream which is always for internal use */
587 if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) {
588 cx18_stop_v4l2_encode_stream(s_idx, 0);
589 clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags);
590 }
591 /* Stop the VBI stream, if only running for internal use */
592 if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
593 !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
594 cx18_stop_v4l2_encode_stream(s_vbi, 0);
595 clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
596 }
560 } 597 }
561 clear_bit(CX18_F_S_STREAMING, &s->s_flags); 598 clear_bit(CX18_F_S_STREAMING, &s->s_flags);
562 cx18_release_stream(s); 599 cx18_release_stream(s); /* Also releases associated streams */
563 return -EIO; 600 return -EIO;
564} 601}
565 602
@@ -618,6 +655,8 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
618{ 655{
619 struct cx18 *cx = id->cx; 656 struct cx18 *cx = id->cx;
620 struct cx18_stream *s = &cx->streams[id->type]; 657 struct cx18_stream *s = &cx->streams[id->type];
658 struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
659 struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
621 660
622 CX18_DEBUG_IOCTL("close() of %s\n", s->name); 661 CX18_DEBUG_IOCTL("close() of %s\n", s->name);
623 662
@@ -625,17 +664,19 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
625 664
626 /* Stop capturing */ 665 /* Stop capturing */
627 if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) { 666 if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
628 struct cx18_stream *s_vbi =
629 &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
630
631 CX18_DEBUG_INFO("close stopping capture\n"); 667 CX18_DEBUG_INFO("close stopping capture\n");
632 /* Special case: a running VBI capture for VBI insertion 668 if (id->type == CX18_ENC_STREAM_TYPE_MPG) {
633 in the mpeg stream. Need to stop that too. */ 669 /* Stop internal use associated VBI and IDX streams */
634 if (id->type == CX18_ENC_STREAM_TYPE_MPG && 670 if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
635 test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && 671 !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
636 !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { 672 CX18_DEBUG_INFO("close stopping embedded VBI "
637 CX18_DEBUG_INFO("close stopping embedded VBI capture\n"); 673 "capture\n");
638 cx18_stop_v4l2_encode_stream(s_vbi, 0); 674 cx18_stop_v4l2_encode_stream(s_vbi, 0);
675 }
676 if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) {
677 CX18_DEBUG_INFO("close stopping IDX capture\n");
678 cx18_stop_v4l2_encode_stream(s_idx, 0);
679 }
639 } 680 }
640 if (id->type == CX18_ENC_STREAM_TYPE_VBI && 681 if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
641 test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) 682 test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags))