diff options
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-fileops.c')
| -rw-r--r-- | drivers/media/video/ivtv/ivtv-fileops.c | 118 |
1 files changed, 44 insertions, 74 deletions
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 38f052257f46..2cd6c89b7d91 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c | |||
| @@ -50,16 +50,16 @@ static int ivtv_claim_stream(struct ivtv_open_id *id, int type) | |||
| 50 | 50 | ||
| 51 | if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { | 51 | if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { |
| 52 | /* someone already claimed this stream */ | 52 | /* someone already claimed this stream */ |
| 53 | if (s->id == id->open_id) { | 53 | if (s->fh == &id->fh) { |
| 54 | /* yes, this file descriptor did. So that's OK. */ | 54 | /* yes, this file descriptor did. So that's OK. */ |
| 55 | return 0; | 55 | return 0; |
| 56 | } | 56 | } |
| 57 | if (s->id == -1 && (type == IVTV_DEC_STREAM_TYPE_VBI || | 57 | if (s->fh == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI || |
| 58 | type == IVTV_ENC_STREAM_TYPE_VBI)) { | 58 | type == IVTV_ENC_STREAM_TYPE_VBI)) { |
| 59 | /* VBI is handled already internally, now also assign | 59 | /* VBI is handled already internally, now also assign |
| 60 | the file descriptor to this stream for external | 60 | the file descriptor to this stream for external |
| 61 | reading of the stream. */ | 61 | reading of the stream. */ |
| 62 | s->id = id->open_id; | 62 | s->fh = &id->fh; |
| 63 | IVTV_DEBUG_INFO("Start Read VBI\n"); | 63 | IVTV_DEBUG_INFO("Start Read VBI\n"); |
| 64 | return 0; | 64 | return 0; |
| 65 | } | 65 | } |
| @@ -67,7 +67,7 @@ static int ivtv_claim_stream(struct ivtv_open_id *id, int type) | |||
| 67 | IVTV_DEBUG_INFO("Stream %d is busy\n", type); | 67 | IVTV_DEBUG_INFO("Stream %d is busy\n", type); |
| 68 | return -EBUSY; | 68 | return -EBUSY; |
| 69 | } | 69 | } |
| 70 | s->id = id->open_id; | 70 | s->fh = &id->fh; |
| 71 | if (type == IVTV_DEC_STREAM_TYPE_VBI) { | 71 | if (type == IVTV_DEC_STREAM_TYPE_VBI) { |
| 72 | /* Enable reinsertion interrupt */ | 72 | /* Enable reinsertion interrupt */ |
| 73 | ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); | 73 | ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); |
| @@ -104,7 +104,7 @@ void ivtv_release_stream(struct ivtv_stream *s) | |||
| 104 | struct ivtv *itv = s->itv; | 104 | struct ivtv *itv = s->itv; |
| 105 | struct ivtv_stream *s_vbi; | 105 | struct ivtv_stream *s_vbi; |
| 106 | 106 | ||
| 107 | s->id = -1; | 107 | s->fh = NULL; |
| 108 | if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) && | 108 | if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) && |
| 109 | test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { | 109 | test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { |
| 110 | /* this stream is still in use internally */ | 110 | /* this stream is still in use internally */ |
| @@ -136,7 +136,7 @@ void ivtv_release_stream(struct ivtv_stream *s) | |||
| 136 | /* was already cleared */ | 136 | /* was already cleared */ |
| 137 | return; | 137 | return; |
| 138 | } | 138 | } |
| 139 | if (s_vbi->id != -1) { | 139 | if (s_vbi->fh) { |
| 140 | /* VBI stream still claimed by a file descriptor */ | 140 | /* VBI stream still claimed by a file descriptor */ |
| 141 | return; | 141 | return; |
| 142 | } | 142 | } |
| @@ -268,11 +268,13 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, | |||
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | /* wait for more data to arrive */ | 270 | /* wait for more data to arrive */ |
| 271 | mutex_unlock(&itv->serialize_lock); | ||
| 271 | prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); | 272 | prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); |
| 272 | /* New buffers might have become available before we were added to the waitqueue */ | 273 | /* New buffers might have become available before we were added to the waitqueue */ |
| 273 | if (!s->q_full.buffers) | 274 | if (!s->q_full.buffers) |
| 274 | schedule(); | 275 | schedule(); |
| 275 | finish_wait(&s->waitq, &wait); | 276 | finish_wait(&s->waitq, &wait); |
| 277 | mutex_lock(&itv->serialize_lock); | ||
| 276 | if (signal_pending(current)) { | 278 | if (signal_pending(current)) { |
| 277 | /* return if a signal was received */ | 279 | /* return if a signal was received */ |
| 278 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); | 280 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); |
| @@ -357,7 +359,7 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co | |||
| 357 | size_t tot_written = 0; | 359 | size_t tot_written = 0; |
| 358 | int single_frame = 0; | 360 | int single_frame = 0; |
| 359 | 361 | ||
| 360 | if (atomic_read(&itv->capturing) == 0 && s->id == -1) { | 362 | if (atomic_read(&itv->capturing) == 0 && s->fh == NULL) { |
| 361 | /* shouldn't happen */ | 363 | /* shouldn't happen */ |
| 362 | IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name); | 364 | IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name); |
| 363 | return -EIO; | 365 | return -EIO; |
| @@ -507,9 +509,7 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_ | |||
| 507 | 509 | ||
| 508 | IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); | 510 | IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); |
| 509 | 511 | ||
| 510 | mutex_lock(&itv->serialize_lock); | ||
| 511 | rc = ivtv_start_capture(id); | 512 | rc = ivtv_start_capture(id); |
| 512 | mutex_unlock(&itv->serialize_lock); | ||
| 513 | if (rc) | 513 | if (rc) |
| 514 | return rc; | 514 | return rc; |
| 515 | return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); | 515 | return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); |
| @@ -584,9 +584,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c | |||
| 584 | set_bit(IVTV_F_S_APPL_IO, &s->s_flags); | 584 | set_bit(IVTV_F_S_APPL_IO, &s->s_flags); |
| 585 | 585 | ||
| 586 | /* Start decoder (returns 0 if already started) */ | 586 | /* Start decoder (returns 0 if already started) */ |
| 587 | mutex_lock(&itv->serialize_lock); | ||
| 588 | rc = ivtv_start_decoding(id, itv->speed); | 587 | rc = ivtv_start_decoding(id, itv->speed); |
| 589 | mutex_unlock(&itv->serialize_lock); | ||
| 590 | if (rc) { | 588 | if (rc) { |
| 591 | IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); | 589 | IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); |
| 592 | 590 | ||
| @@ -627,11 +625,13 @@ retry: | |||
| 627 | break; | 625 | break; |
| 628 | if (filp->f_flags & O_NONBLOCK) | 626 | if (filp->f_flags & O_NONBLOCK) |
| 629 | return -EAGAIN; | 627 | return -EAGAIN; |
| 628 | mutex_unlock(&itv->serialize_lock); | ||
| 630 | prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); | 629 | prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); |
| 631 | /* New buffers might have become free before we were added to the waitqueue */ | 630 | /* New buffers might have become free before we were added to the waitqueue */ |
| 632 | if (!s->q_free.buffers) | 631 | if (!s->q_free.buffers) |
| 633 | schedule(); | 632 | schedule(); |
| 634 | finish_wait(&s->waitq, &wait); | 633 | finish_wait(&s->waitq, &wait); |
| 634 | mutex_lock(&itv->serialize_lock); | ||
| 635 | if (signal_pending(current)) { | 635 | if (signal_pending(current)) { |
| 636 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); | 636 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); |
| 637 | return -EINTR; | 637 | return -EINTR; |
| @@ -686,12 +686,14 @@ retry: | |||
| 686 | if (mode == OUT_YUV) | 686 | if (mode == OUT_YUV) |
| 687 | ivtv_yuv_setup_stream_frame(itv); | 687 | ivtv_yuv_setup_stream_frame(itv); |
| 688 | 688 | ||
| 689 | mutex_unlock(&itv->serialize_lock); | ||
| 689 | prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); | 690 | prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); |
| 690 | while (!(got_sig = signal_pending(current)) && | 691 | while (!(got_sig = signal_pending(current)) && |
| 691 | test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { | 692 | test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { |
| 692 | schedule(); | 693 | schedule(); |
| 693 | } | 694 | } |
| 694 | finish_wait(&itv->dma_waitq, &wait); | 695 | finish_wait(&itv->dma_waitq, &wait); |
| 696 | mutex_lock(&itv->serialize_lock); | ||
| 695 | if (got_sig) { | 697 | if (got_sig) { |
| 696 | IVTV_DEBUG_INFO("User interrupted %s\n", s->name); | 698 | IVTV_DEBUG_INFO("User interrupted %s\n", s->name); |
| 697 | return -EINTR; | 699 | return -EINTR; |
| @@ -756,9 +758,7 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) | |||
| 756 | if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | 758 | if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { |
| 757 | int rc; | 759 | int rc; |
| 758 | 760 | ||
| 759 | mutex_lock(&itv->serialize_lock); | ||
| 760 | rc = ivtv_start_capture(id); | 761 | rc = ivtv_start_capture(id); |
| 761 | mutex_unlock(&itv->serialize_lock); | ||
| 762 | if (rc) { | 762 | if (rc) { |
| 763 | IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", | 763 | IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", |
| 764 | s->name, rc); | 764 | s->name, rc); |
| @@ -808,7 +808,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) | |||
| 808 | id->type == IVTV_ENC_STREAM_TYPE_VBI) && | 808 | id->type == IVTV_ENC_STREAM_TYPE_VBI) && |
| 809 | test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { | 809 | test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { |
| 810 | /* Also used internally, don't stop capturing */ | 810 | /* Also used internally, don't stop capturing */ |
| 811 | s->id = -1; | 811 | s->fh = NULL; |
| 812 | } | 812 | } |
| 813 | else { | 813 | else { |
| 814 | ivtv_stop_v4l2_encode_stream(s, gop_end); | 814 | ivtv_stop_v4l2_encode_stream(s, gop_end); |
| @@ -861,20 +861,9 @@ int ivtv_v4l2_close(struct file *filp) | |||
| 861 | 861 | ||
| 862 | IVTV_DEBUG_FILE("close %s\n", s->name); | 862 | IVTV_DEBUG_FILE("close %s\n", s->name); |
| 863 | 863 | ||
| 864 | v4l2_fh_del(fh); | ||
| 865 | v4l2_fh_exit(fh); | ||
| 866 | |||
| 867 | /* Easy case first: this stream was never claimed by us */ | ||
| 868 | if (s->id != id->open_id) { | ||
| 869 | kfree(id); | ||
| 870 | return 0; | ||
| 871 | } | ||
| 872 | |||
| 873 | /* 'Unclaim' this stream */ | ||
| 874 | |||
| 875 | /* Stop radio */ | 864 | /* Stop radio */ |
| 876 | mutex_lock(&itv->serialize_lock); | 865 | if (id->type == IVTV_ENC_STREAM_TYPE_RAD && |
| 877 | if (id->type == IVTV_ENC_STREAM_TYPE_RAD) { | 866 | v4l2_fh_is_singular_file(filp)) { |
| 878 | /* Closing radio device, return to TV mode */ | 867 | /* Closing radio device, return to TV mode */ |
| 879 | ivtv_mute(itv); | 868 | ivtv_mute(itv); |
| 880 | /* Mark that the radio is no longer in use */ | 869 | /* Mark that the radio is no longer in use */ |
| @@ -890,13 +879,25 @@ int ivtv_v4l2_close(struct file *filp) | |||
| 890 | if (atomic_read(&itv->capturing) > 0) { | 879 | if (atomic_read(&itv->capturing) > 0) { |
| 891 | /* Undo video mute */ | 880 | /* Undo video mute */ |
| 892 | ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, | 881 | ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, |
| 893 | v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) | | 882 | v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) | |
| 894 | (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8)); | 883 | (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8)); |
| 895 | } | 884 | } |
| 896 | /* Done! Unmute and continue. */ | 885 | /* Done! Unmute and continue. */ |
| 897 | ivtv_unmute(itv); | 886 | ivtv_unmute(itv); |
| 898 | ivtv_release_stream(s); | 887 | } |
| 899 | } else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { | 888 | |
| 889 | v4l2_fh_del(fh); | ||
| 890 | v4l2_fh_exit(fh); | ||
| 891 | |||
| 892 | /* Easy case first: this stream was never claimed by us */ | ||
| 893 | if (s->fh != &id->fh) { | ||
| 894 | kfree(id); | ||
| 895 | return 0; | ||
| 896 | } | ||
| 897 | |||
| 898 | /* 'Unclaim' this stream */ | ||
| 899 | |||
| 900 | if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { | ||
| 900 | struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT]; | 901 | struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT]; |
| 901 | 902 | ||
| 902 | ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); | 903 | ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); |
| @@ -911,21 +912,25 @@ int ivtv_v4l2_close(struct file *filp) | |||
| 911 | ivtv_stop_capture(id, 0); | 912 | ivtv_stop_capture(id, 0); |
| 912 | } | 913 | } |
| 913 | kfree(id); | 914 | kfree(id); |
| 914 | mutex_unlock(&itv->serialize_lock); | ||
| 915 | return 0; | 915 | return 0; |
| 916 | } | 916 | } |
| 917 | 917 | ||
| 918 | static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) | 918 | int ivtv_v4l2_open(struct file *filp) |
| 919 | { | 919 | { |
| 920 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
| 921 | struct video_device *vdev = video_devdata(filp); | 920 | struct video_device *vdev = video_devdata(filp); |
| 922 | #endif | 921 | struct ivtv_stream *s = video_get_drvdata(vdev); |
| 923 | struct ivtv *itv = s->itv; | 922 | struct ivtv *itv = s->itv; |
| 924 | struct ivtv_open_id *item; | 923 | struct ivtv_open_id *item; |
| 925 | int res = 0; | 924 | int res = 0; |
| 926 | 925 | ||
| 927 | IVTV_DEBUG_FILE("open %s\n", s->name); | 926 | IVTV_DEBUG_FILE("open %s\n", s->name); |
| 928 | 927 | ||
| 928 | if (ivtv_init_on_first_open(itv)) { | ||
| 929 | IVTV_ERR("Failed to initialize on device %s\n", | ||
| 930 | video_device_node_name(vdev)); | ||
| 931 | return -ENXIO; | ||
| 932 | } | ||
| 933 | |||
| 929 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 934 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 930 | /* Unless ivtv_fw_debug is set, error out if firmware dead. */ | 935 | /* Unless ivtv_fw_debug is set, error out if firmware dead. */ |
| 931 | if (ivtv_fw_debug) { | 936 | if (ivtv_fw_debug) { |
| @@ -966,31 +971,19 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) | |||
| 966 | return -ENOMEM; | 971 | return -ENOMEM; |
| 967 | } | 972 | } |
| 968 | v4l2_fh_init(&item->fh, s->vdev); | 973 | v4l2_fh_init(&item->fh, s->vdev); |
| 969 | if (res < 0) { | ||
| 970 | v4l2_fh_exit(&item->fh); | ||
| 971 | kfree(item); | ||
| 972 | return res; | ||
| 973 | } | ||
| 974 | item->itv = itv; | 974 | item->itv = itv; |
| 975 | item->type = s->type; | 975 | item->type = s->type; |
| 976 | 976 | ||
| 977 | item->open_id = itv->open_id++; | ||
| 978 | filp->private_data = &item->fh; | 977 | filp->private_data = &item->fh; |
| 978 | v4l2_fh_add(&item->fh); | ||
| 979 | 979 | ||
| 980 | if (item->type == IVTV_ENC_STREAM_TYPE_RAD) { | 980 | if (item->type == IVTV_ENC_STREAM_TYPE_RAD && |
| 981 | /* Try to claim this stream */ | 981 | v4l2_fh_is_singular_file(filp)) { |
| 982 | if (ivtv_claim_stream(item, item->type)) { | ||
| 983 | /* No, it's already in use */ | ||
| 984 | v4l2_fh_exit(&item->fh); | ||
| 985 | kfree(item); | ||
| 986 | return -EBUSY; | ||
| 987 | } | ||
| 988 | |||
| 989 | if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { | 982 | if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { |
| 990 | if (atomic_read(&itv->capturing) > 0) { | 983 | if (atomic_read(&itv->capturing) > 0) { |
| 991 | /* switching to radio while capture is | 984 | /* switching to radio while capture is |
| 992 | in progress is not polite */ | 985 | in progress is not polite */ |
| 993 | ivtv_release_stream(s); | 986 | v4l2_fh_del(&item->fh); |
| 994 | v4l2_fh_exit(&item->fh); | 987 | v4l2_fh_exit(&item->fh); |
| 995 | kfree(item); | 988 | kfree(item); |
| 996 | return -EBUSY; | 989 | return -EBUSY; |
| @@ -1022,32 +1015,9 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) | |||
| 1022 | 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); | 1015 | 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); |
| 1023 | itv->yuv_info.stream_size = 0; | 1016 | itv->yuv_info.stream_size = 0; |
| 1024 | } | 1017 | } |
| 1025 | v4l2_fh_add(&item->fh); | ||
| 1026 | return 0; | 1018 | return 0; |
| 1027 | } | 1019 | } |
| 1028 | 1020 | ||
| 1029 | int ivtv_v4l2_open(struct file *filp) | ||
| 1030 | { | ||
| 1031 | int res; | ||
| 1032 | struct ivtv *itv = NULL; | ||
| 1033 | struct ivtv_stream *s = NULL; | ||
| 1034 | struct video_device *vdev = video_devdata(filp); | ||
| 1035 | |||
| 1036 | s = video_get_drvdata(vdev); | ||
| 1037 | itv = s->itv; | ||
| 1038 | |||
| 1039 | mutex_lock(&itv->serialize_lock); | ||
| 1040 | if (ivtv_init_on_first_open(itv)) { | ||
| 1041 | IVTV_ERR("Failed to initialize on device %s\n", | ||
| 1042 | video_device_node_name(vdev)); | ||
| 1043 | mutex_unlock(&itv->serialize_lock); | ||
| 1044 | return -ENXIO; | ||
| 1045 | } | ||
| 1046 | res = ivtv_serialized_open(s, filp); | ||
| 1047 | mutex_unlock(&itv->serialize_lock); | ||
| 1048 | return res; | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | void ivtv_mute(struct ivtv *itv) | 1021 | void ivtv_mute(struct ivtv *itv) |
| 1052 | { | 1022 | { |
| 1053 | if (atomic_read(&itv->capturing)) | 1023 | if (atomic_read(&itv->capturing)) |
