diff options
Diffstat (limited to 'drivers/media/video/cx18/cx18-fileops.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-fileops.c | 183 |
1 files changed, 118 insertions, 65 deletions
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index c0885c69fd89..b1ad03f61019 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. */ |
43 | static int cx18_claim_stream(struct cx18_open_id *id, int type) | 43 | static int 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,21 +73,27 @@ 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 | } |
87 | 99 | ||
@@ -90,9 +102,17 @@ static int cx18_claim_stream(struct cx18_open_id *id, int type) | |||
90 | static void cx18_release_stream(struct cx18_stream *s) | 102 | static void cx18_release_stream(struct cx18_stream *s) |
91 | { | 103 | { |
92 | struct cx18 *cx = s->cx; | 104 | struct cx18 *cx = s->cx; |
93 | struct cx18_stream *s_vbi; | 105 | struct cx18_stream *s_assoc; |
94 | 106 | ||
95 | s->id = -1; | 107 | s->id = -1; |
108 | if (s->type == CX18_ENC_STREAM_TYPE_IDX) { | ||
109 | /* | ||
110 | * The IDX stream is only used internally, and can | ||
111 | * only be indirectly unclaimed by unclaiming the MPG stream. | ||
112 | */ | ||
113 | return; | ||
114 | } | ||
115 | |||
96 | if (s->type == CX18_ENC_STREAM_TYPE_VBI && | 116 | if (s->type == CX18_ENC_STREAM_TYPE_VBI && |
97 | test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) { | 117 | test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) { |
98 | /* this stream is still in use internally */ | 118 | /* this stream is still in use internally */ |
@@ -105,24 +125,34 @@ static void cx18_release_stream(struct cx18_stream *s) | |||
105 | 125 | ||
106 | cx18_flush_queues(s); | 126 | cx18_flush_queues(s); |
107 | 127 | ||
108 | /* CX18_ENC_STREAM_TYPE_MPG needs to release CX18_ENC_STREAM_TYPE_VBI, | 128 | /* |
109 | for all other streams we're done */ | 129 | * CX18_ENC_STREAM_TYPE_MPG needs to release the |
110 | if (s->type == CX18_ENC_STREAM_TYPE_MPG) | 130 | * CX18_ENC_STREAM_TYPE_VBI and/or CX18_ENC_STREAM_TYPE_IDX streams. |
111 | s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; | 131 | * |
112 | else | 132 | * For all other streams we're done. |
133 | */ | ||
134 | if (s->type != CX18_ENC_STREAM_TYPE_MPG) | ||
113 | return; | 135 | return; |
114 | 136 | ||
115 | /* clear internal use flag */ | 137 | /* Unclaim the associated MPEG Index stream */ |
116 | if (!test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags)) { | 138 | s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; |
117 | /* was already cleared */ | 139 | if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) { |
118 | return; | 140 | clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); |
141 | cx18_flush_queues(s_assoc); | ||
119 | } | 142 | } |
120 | if (s_vbi->id != -1) { | 143 | |
121 | /* VBI stream still claimed by a file descriptor */ | 144 | /* Unclaim the associated VBI stream */ |
122 | return; | 145 | s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; |
146 | if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) { | ||
147 | if (s_assoc->id == -1) { | ||
148 | /* | ||
149 | * The VBI stream is not still claimed by a file | ||
150 | * descriptor, so completely unclaim it. | ||
151 | */ | ||
152 | clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); | ||
153 | cx18_flush_queues(s_assoc); | ||
154 | } | ||
123 | } | 155 | } |
124 | clear_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags); | ||
125 | cx18_flush_queues(s_vbi); | ||
126 | } | 156 | } |
127 | 157 | ||
128 | static void cx18_dualwatch(struct cx18 *cx) | 158 | static void cx18_dualwatch(struct cx18 *cx) |
@@ -498,6 +528,7 @@ int cx18_start_capture(struct cx18_open_id *id) | |||
498 | struct cx18 *cx = id->cx; | 528 | struct cx18 *cx = id->cx; |
499 | struct cx18_stream *s = &cx->streams[id->type]; | 529 | struct cx18_stream *s = &cx->streams[id->type]; |
500 | struct cx18_stream *s_vbi; | 530 | struct cx18_stream *s_vbi; |
531 | struct cx18_stream *s_idx; | ||
501 | 532 | ||
502 | if (s->type == CX18_ENC_STREAM_TYPE_RAD) { | 533 | if (s->type == CX18_ENC_STREAM_TYPE_RAD) { |
503 | /* you cannot read from these stream types. */ | 534 | /* you cannot read from these stream types. */ |
@@ -516,25 +547,33 @@ int cx18_start_capture(struct cx18_open_id *id) | |||
516 | return 0; | 547 | return 0; |
517 | } | 548 | } |
518 | 549 | ||
519 | /* Start VBI capture if required */ | 550 | /* Start associated VBI or IDX stream capture if required */ |
520 | s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; | 551 | s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; |
521 | if (s->type == CX18_ENC_STREAM_TYPE_MPG && | 552 | s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; |
522 | test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && | 553 | if (s->type == CX18_ENC_STREAM_TYPE_MPG) { |
523 | !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { | 554 | /* |
524 | /* Note: the CX18_ENC_STREAM_TYPE_VBI is claimed | 555 | * The VBI and IDX streams should have been claimed |
525 | automatically when the MPG stream is claimed. | 556 | * automatically, if for internal use, when the MPG stream was |
526 | We only need to start the VBI capturing. */ | 557 | * claimed. We only need to start these streams capturing. |
527 | if (cx18_start_v4l2_encode_stream(s_vbi)) { | 558 | */ |
528 | CX18_DEBUG_WARN("VBI capture start failed\n"); | 559 | if (test_bit(CX18_F_S_INTERNAL_USE, &s_idx->s_flags) && |
529 | 560 | !test_and_set_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { | |
530 | /* Failure, clean up and return an error */ | 561 | if (cx18_start_v4l2_encode_stream(s_idx)) { |
531 | clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); | 562 | CX18_DEBUG_WARN("IDX capture start failed\n"); |
532 | clear_bit(CX18_F_S_STREAMING, &s->s_flags); | 563 | clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags); |
533 | /* also releases the associated VBI stream */ | 564 | goto start_failed; |
534 | cx18_release_stream(s); | 565 | } |
535 | return -EIO; | 566 | CX18_DEBUG_INFO("IDX capture started\n"); |
567 | } | ||
568 | if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && | ||
569 | !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { | ||
570 | if (cx18_start_v4l2_encode_stream(s_vbi)) { | ||
571 | CX18_DEBUG_WARN("VBI capture start failed\n"); | ||
572 | clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); | ||
573 | goto start_failed; | ||
574 | } | ||
575 | CX18_DEBUG_INFO("VBI insertion started\n"); | ||
536 | } | 576 | } |
537 | CX18_DEBUG_INFO("VBI insertion started\n"); | ||
538 | } | 577 | } |
539 | 578 | ||
540 | /* Tell the card to start capturing */ | 579 | /* Tell the card to start capturing */ |
@@ -547,19 +586,29 @@ int cx18_start_capture(struct cx18_open_id *id) | |||
547 | return 0; | 586 | return 0; |
548 | } | 587 | } |
549 | 588 | ||
550 | /* failure, clean up */ | 589 | start_failed: |
551 | CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); | 590 | CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); |
552 | 591 | ||
553 | /* Note: the CX18_ENC_STREAM_TYPE_VBI is released | 592 | /* |
554 | automatically when the MPG stream is released. | 593 | * The associated VBI and IDX streams for internal use are released |
555 | We only need to stop the VBI capturing. */ | 594 | * automatically when the MPG stream is released. We only need to stop |
556 | if (s->type == CX18_ENC_STREAM_TYPE_MPG && | 595 | * the associated stream. |
557 | test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { | 596 | */ |
558 | cx18_stop_v4l2_encode_stream(s_vbi, 0); | 597 | if (s->type == CX18_ENC_STREAM_TYPE_MPG) { |
559 | clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); | 598 | /* Stop the IDX stream which is always for internal use */ |
599 | if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { | ||
600 | cx18_stop_v4l2_encode_stream(s_idx, 0); | ||
601 | clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags); | ||
602 | } | ||
603 | /* Stop the VBI stream, if only running for internal use */ | ||
604 | if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && | ||
605 | !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { | ||
606 | cx18_stop_v4l2_encode_stream(s_vbi, 0); | ||
607 | clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); | ||
608 | } | ||
560 | } | 609 | } |
561 | clear_bit(CX18_F_S_STREAMING, &s->s_flags); | 610 | clear_bit(CX18_F_S_STREAMING, &s->s_flags); |
562 | cx18_release_stream(s); | 611 | cx18_release_stream(s); /* Also releases associated streams */ |
563 | return -EIO; | 612 | return -EIO; |
564 | } | 613 | } |
565 | 614 | ||
@@ -618,6 +667,8 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end) | |||
618 | { | 667 | { |
619 | struct cx18 *cx = id->cx; | 668 | struct cx18 *cx = id->cx; |
620 | struct cx18_stream *s = &cx->streams[id->type]; | 669 | struct cx18_stream *s = &cx->streams[id->type]; |
670 | struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; | ||
671 | struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; | ||
621 | 672 | ||
622 | CX18_DEBUG_IOCTL("close() of %s\n", s->name); | 673 | CX18_DEBUG_IOCTL("close() of %s\n", s->name); |
623 | 674 | ||
@@ -625,17 +676,19 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end) | |||
625 | 676 | ||
626 | /* Stop capturing */ | 677 | /* Stop capturing */ |
627 | if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) { | 678 | 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"); | 679 | CX18_DEBUG_INFO("close stopping capture\n"); |
632 | /* Special case: a running VBI capture for VBI insertion | 680 | if (id->type == CX18_ENC_STREAM_TYPE_MPG) { |
633 | in the mpeg stream. Need to stop that too. */ | 681 | /* Stop internal use associated VBI and IDX streams */ |
634 | if (id->type == CX18_ENC_STREAM_TYPE_MPG && | 682 | if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && |
635 | test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && | 683 | !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { |
636 | !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { | 684 | CX18_DEBUG_INFO("close stopping embedded VBI " |
637 | CX18_DEBUG_INFO("close stopping embedded VBI capture\n"); | 685 | "capture\n"); |
638 | cx18_stop_v4l2_encode_stream(s_vbi, 0); | 686 | cx18_stop_v4l2_encode_stream(s_vbi, 0); |
687 | } | ||
688 | if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { | ||
689 | CX18_DEBUG_INFO("close stopping IDX capture\n"); | ||
690 | cx18_stop_v4l2_encode_stream(s_idx, 0); | ||
691 | } | ||
639 | } | 692 | } |
640 | if (id->type == CX18_ENC_STREAM_TYPE_VBI && | 693 | if (id->type == CX18_ENC_STREAM_TYPE_VBI && |
641 | test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) | 694 | test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) |