diff options
Diffstat (limited to 'drivers/media/video/cx18/cx18-fileops.c')
| -rw-r--r-- | drivers/media/video/cx18/cx18-fileops.c | 205 |
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. */ |
| 43 | static int cx18_claim_stream(struct cx18_open_id *id, int type) | 43 | 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,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 | } |
| 99 | EXPORT_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. */ |
| 90 | static void cx18_release_stream(struct cx18_stream *s) | 103 | void 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 | } |
| 158 | EXPORT_SYMBOL(cx18_release_stream); | ||
| 127 | 159 | ||
| 128 | static void cx18_dualwatch(struct cx18 *cx) | 160 | static 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 | |||
| 377 | static size_t cx18_copy_mdl_to_user(struct cx18_stream *s, | 395 | static 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 */ | 577 | start_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)) |
