aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18/cx18-ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx18/cx18-ioctl.c')
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c135
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
778static 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
833static 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
778static int cx18_g_enc_index(struct file *file, void *fh, 870static 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
784static int cx18_encoder_cmd(struct file *file, void *fh, 917static int cx18_encoder_cmd(struct file *file, void *fh,