diff options
Diffstat (limited to 'drivers/media/video/cx18/cx18-ioctl.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.c | 135 |
1 files changed, 134 insertions, 1 deletions
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 3e4fc192fdec..b81dd0ea8eb9 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c | |||
@@ -775,10 +775,143 @@ static int cx18_g_sliced_vbi_cap(struct file *file, void *fh, | |||
775 | return 0; | 775 | return 0; |
776 | } | 776 | } |
777 | 777 | ||
778 | static int _cx18_process_idx_data(struct cx18_buffer *buf, | ||
779 | struct v4l2_enc_idx *idx) | ||
780 | { | ||
781 | int consumed, remaining; | ||
782 | struct v4l2_enc_idx_entry *e_idx; | ||
783 | struct cx18_enc_idx_entry *e_buf; | ||
784 | |||
785 | /* Frame type lookup: 1=I, 2=P, 4=B */ | ||
786 | const int mapping[8] = { | ||
787 | -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, | ||
788 | -1, V4L2_ENC_IDX_FRAME_B, -1, -1, -1 | ||
789 | }; | ||
790 | |||
791 | /* | ||
792 | * Assumption here is that a buf holds an integral number of | ||
793 | * struct cx18_enc_idx_entry objects and is properly aligned. | ||
794 | * This is enforced by the module options on IDX buffer sizes. | ||
795 | */ | ||
796 | remaining = buf->bytesused - buf->readpos; | ||
797 | consumed = 0; | ||
798 | e_idx = &idx->entry[idx->entries]; | ||
799 | e_buf = (struct cx18_enc_idx_entry *) &buf->buf[buf->readpos]; | ||
800 | |||
801 | while (remaining >= sizeof(struct cx18_enc_idx_entry) && | ||
802 | idx->entries < V4L2_ENC_IDX_ENTRIES) { | ||
803 | |||
804 | e_idx->offset = (((u64) le32_to_cpu(e_buf->offset_high)) << 32) | ||
805 | | le32_to_cpu(e_buf->offset_low); | ||
806 | |||
807 | e_idx->pts = (((u64) (le32_to_cpu(e_buf->pts_high) & 1)) << 32) | ||
808 | | le32_to_cpu(e_buf->pts_low); | ||
809 | |||
810 | e_idx->length = le32_to_cpu(e_buf->length); | ||
811 | |||
812 | e_idx->flags = mapping[le32_to_cpu(e_buf->flags) & 0x7]; | ||
813 | |||
814 | e_idx->reserved[0] = 0; | ||
815 | e_idx->reserved[1] = 0; | ||
816 | |||
817 | idx->entries++; | ||
818 | e_idx = &idx->entry[idx->entries]; | ||
819 | e_buf++; | ||
820 | |||
821 | remaining -= sizeof(struct cx18_enc_idx_entry); | ||
822 | consumed += sizeof(struct cx18_enc_idx_entry); | ||
823 | } | ||
824 | |||
825 | /* Swallow any partial entries at the end, if there are any */ | ||
826 | if (remaining > 0 && remaining < sizeof(struct cx18_enc_idx_entry)) | ||
827 | consumed += remaining; | ||
828 | |||
829 | buf->readpos += consumed; | ||
830 | return consumed; | ||
831 | } | ||
832 | |||
833 | static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl, | ||
834 | struct v4l2_enc_idx *idx) | ||
835 | { | ||
836 | if (s->type != CX18_ENC_STREAM_TYPE_IDX) | ||
837 | return -EINVAL; | ||
838 | |||
839 | if (mdl->curr_buf == NULL) | ||
840 | mdl->curr_buf = list_first_entry(&mdl->buf_list, | ||
841 | struct cx18_buffer, list); | ||
842 | |||
843 | if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { | ||
844 | /* | ||
845 | * For some reason we've exhausted the buffers, but the MDL | ||
846 | * object still said some data was unread. | ||
847 | * Fix that and bail out. | ||
848 | */ | ||
849 | mdl->readpos = mdl->bytesused; | ||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) { | ||
854 | |||
855 | /* Skip any empty buffers in the MDL */ | ||
856 | if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused) | ||
857 | continue; | ||
858 | |||
859 | mdl->readpos += _cx18_process_idx_data(mdl->curr_buf, idx); | ||
860 | |||
861 | /* exit when MDL drained or request satisfied */ | ||
862 | if (idx->entries >= V4L2_ENC_IDX_ENTRIES || | ||
863 | mdl->curr_buf->readpos < mdl->curr_buf->bytesused || | ||
864 | mdl->readpos >= mdl->bytesused) | ||
865 | break; | ||
866 | } | ||
867 | return 0; | ||
868 | } | ||
869 | |||
778 | static int cx18_g_enc_index(struct file *file, void *fh, | 870 | static int cx18_g_enc_index(struct file *file, void *fh, |
779 | struct v4l2_enc_idx *idx) | 871 | struct v4l2_enc_idx *idx) |
780 | { | 872 | { |
781 | return -EINVAL; | 873 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; |
874 | struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; | ||
875 | s32 tmp; | ||
876 | struct cx18_mdl *mdl; | ||
877 | |||
878 | if (!cx18_stream_enabled(s)) /* Module options inhibited IDX stream */ | ||
879 | return -EINVAL; | ||
880 | |||
881 | /* Compute the best case number of entries we can buffer */ | ||
882 | tmp = s->buffers - | ||
883 | s->bufs_per_mdl * CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN; | ||
884 | if (tmp <= 0) | ||
885 | tmp = 1; | ||
886 | tmp = tmp * s->buf_size / sizeof(struct cx18_enc_idx_entry); | ||
887 | |||
888 | /* Fill out the header of the return structure */ | ||
889 | idx->entries = 0; | ||
890 | idx->entries_cap = tmp; | ||
891 | memset(idx->reserved, 0, sizeof(idx->reserved)); | ||
892 | |||
893 | /* Pull IDX MDLs and buffers from q_full and populate the entries */ | ||
894 | do { | ||
895 | mdl = cx18_dequeue(s, &s->q_full); | ||
896 | if (mdl == NULL) /* No more IDX data right now */ | ||
897 | break; | ||
898 | |||
899 | /* Extract the Index entry data from the MDL and buffers */ | ||
900 | cx18_process_idx_data(s, mdl, idx); | ||
901 | if (mdl->readpos < mdl->bytesused) { | ||
902 | /* We finished with data remaining, push the MDL back */ | ||
903 | cx18_push(s, mdl, &s->q_full); | ||
904 | break; | ||
905 | } | ||
906 | |||
907 | /* We drained this MDL, schedule it to go to the firmware */ | ||
908 | cx18_enqueue(s, mdl, &s->q_free); | ||
909 | |||
910 | } while (idx->entries < V4L2_ENC_IDX_ENTRIES); | ||
911 | |||
912 | /* Tell the work handler to send free IDX MDLs to the firmware */ | ||
913 | cx18_stream_load_fw_queue(s); | ||
914 | return 0; | ||
782 | } | 915 | } |
783 | 916 | ||
784 | static int cx18_encoder_cmd(struct file *file, void *fh, | 917 | static int cx18_encoder_cmd(struct file *file, void *fh, |