diff options
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/usb/hdpvr/hdpvr-video.c | 217 | ||||
-rw-r--r-- | drivers/media/usb/hdpvr/hdpvr.h | 1 |
2 files changed, 194 insertions, 24 deletions
diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 042f204972a4..43763097d9bf 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | 22 | ||
23 | #include <linux/videodev2.h> | 23 | #include <linux/videodev2.h> |
24 | #include <linux/v4l2-dv-timings.h> | ||
24 | #include <media/v4l2-dev.h> | 25 | #include <media/v4l2-dev.h> |
25 | #include <media/v4l2-common.h> | 26 | #include <media/v4l2-common.h> |
26 | #include <media/v4l2-ioctl.h> | 27 | #include <media/v4l2-ioctl.h> |
@@ -36,6 +37,25 @@ | |||
36 | list_size(&dev->free_buff_list), \ | 37 | list_size(&dev->free_buff_list), \ |
37 | list_size(&dev->rec_buff_list)); } | 38 | list_size(&dev->rec_buff_list)); } |
38 | 39 | ||
40 | static const struct v4l2_dv_timings hdpvr_dv_timings[] = { | ||
41 | V4L2_DV_BT_CEA_720X480I59_94, | ||
42 | V4L2_DV_BT_CEA_720X576I50, | ||
43 | V4L2_DV_BT_CEA_720X480P59_94, | ||
44 | V4L2_DV_BT_CEA_720X576P50, | ||
45 | V4L2_DV_BT_CEA_1280X720P50, | ||
46 | V4L2_DV_BT_CEA_1280X720P60, | ||
47 | V4L2_DV_BT_CEA_1920X1080I50, | ||
48 | V4L2_DV_BT_CEA_1920X1080I60, | ||
49 | }; | ||
50 | |||
51 | /* Use 480i59 as the default timings */ | ||
52 | #define HDPVR_DEF_DV_TIMINGS_IDX (0) | ||
53 | |||
54 | struct hdpvr_fh { | ||
55 | struct v4l2_fh fh; | ||
56 | bool legacy_mode; | ||
57 | }; | ||
58 | |||
39 | static uint list_size(struct list_head *list) | 59 | static uint list_size(struct list_head *list) |
40 | { | 60 | { |
41 | struct list_head *tmp; | 61 | struct list_head *tmp; |
@@ -355,13 +375,23 @@ static int hdpvr_stop_streaming(struct hdpvr_device *dev) | |||
355 | * video 4 linux 2 file operations | 375 | * video 4 linux 2 file operations |
356 | */ | 376 | */ |
357 | 377 | ||
378 | static int hdpvr_open(struct file *file) | ||
379 | { | ||
380 | struct hdpvr_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
381 | |||
382 | if (fh == NULL) | ||
383 | return -ENOMEM; | ||
384 | fh->legacy_mode = true; | ||
385 | v4l2_fh_init(&fh->fh, video_devdata(file)); | ||
386 | v4l2_fh_add(&fh->fh); | ||
387 | file->private_data = fh; | ||
388 | return 0; | ||
389 | } | ||
390 | |||
358 | static int hdpvr_release(struct file *file) | 391 | static int hdpvr_release(struct file *file) |
359 | { | 392 | { |
360 | struct hdpvr_device *dev = video_drvdata(file); | 393 | struct hdpvr_device *dev = video_drvdata(file); |
361 | 394 | ||
362 | if (!dev) | ||
363 | return -ENODEV; | ||
364 | |||
365 | mutex_lock(&dev->io_mutex); | 395 | mutex_lock(&dev->io_mutex); |
366 | if (file->private_data == dev->owner) { | 396 | if (file->private_data == dev->owner) { |
367 | hdpvr_stop_streaming(dev); | 397 | hdpvr_stop_streaming(dev); |
@@ -388,9 +418,6 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, | |||
388 | if (*pos) | 418 | if (*pos) |
389 | return -ESPIPE; | 419 | return -ESPIPE; |
390 | 420 | ||
391 | if (!dev) | ||
392 | return -ENODEV; | ||
393 | |||
394 | mutex_lock(&dev->io_mutex); | 421 | mutex_lock(&dev->io_mutex); |
395 | if (dev->status == STATUS_IDLE) { | 422 | if (dev->status == STATUS_IDLE) { |
396 | if (hdpvr_start_streaming(dev)) { | 423 | if (hdpvr_start_streaming(dev)) { |
@@ -518,7 +545,7 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait) | |||
518 | 545 | ||
519 | static const struct v4l2_file_operations hdpvr_fops = { | 546 | static const struct v4l2_file_operations hdpvr_fops = { |
520 | .owner = THIS_MODULE, | 547 | .owner = THIS_MODULE, |
521 | .open = v4l2_fh_open, | 548 | .open = hdpvr_open, |
522 | .release = hdpvr_release, | 549 | .release = hdpvr_release, |
523 | .read = hdpvr_read, | 550 | .read = hdpvr_read, |
524 | .poll = hdpvr_poll, | 551 | .poll = hdpvr_poll, |
@@ -594,6 +621,121 @@ static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *a) | |||
594 | return 0; | 621 | return 0; |
595 | } | 622 | } |
596 | 623 | ||
624 | static int vidioc_s_dv_timings(struct file *file, void *_fh, | ||
625 | struct v4l2_dv_timings *timings) | ||
626 | { | ||
627 | struct hdpvr_device *dev = video_drvdata(file); | ||
628 | struct hdpvr_fh *fh = _fh; | ||
629 | int i; | ||
630 | |||
631 | fh->legacy_mode = false; | ||
632 | if (dev->options.video_input) | ||
633 | return -ENODATA; | ||
634 | if (dev->status != STATUS_IDLE) | ||
635 | return -EBUSY; | ||
636 | for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) | ||
637 | if (v4l_match_dv_timings(timings, hdpvr_dv_timings + i, 0)) | ||
638 | break; | ||
639 | if (i == ARRAY_SIZE(hdpvr_dv_timings)) | ||
640 | return -EINVAL; | ||
641 | dev->cur_dv_timings = hdpvr_dv_timings[i]; | ||
642 | dev->width = hdpvr_dv_timings[i].bt.width; | ||
643 | dev->height = hdpvr_dv_timings[i].bt.height; | ||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int vidioc_g_dv_timings(struct file *file, void *_fh, | ||
648 | struct v4l2_dv_timings *timings) | ||
649 | { | ||
650 | struct hdpvr_device *dev = video_drvdata(file); | ||
651 | struct hdpvr_fh *fh = _fh; | ||
652 | |||
653 | fh->legacy_mode = false; | ||
654 | if (dev->options.video_input) | ||
655 | return -ENODATA; | ||
656 | *timings = dev->cur_dv_timings; | ||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | static int vidioc_query_dv_timings(struct file *file, void *_fh, | ||
661 | struct v4l2_dv_timings *timings) | ||
662 | { | ||
663 | struct hdpvr_device *dev = video_drvdata(file); | ||
664 | struct hdpvr_fh *fh = _fh; | ||
665 | struct hdpvr_video_info *vid_info; | ||
666 | bool interlaced; | ||
667 | int ret = 0; | ||
668 | int i; | ||
669 | |||
670 | fh->legacy_mode = false; | ||
671 | if (dev->options.video_input) | ||
672 | return -ENODATA; | ||
673 | vid_info = get_video_info(dev); | ||
674 | if (vid_info == NULL) | ||
675 | return -ENOLCK; | ||
676 | interlaced = vid_info->fps <= 30; | ||
677 | for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) { | ||
678 | const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt; | ||
679 | unsigned hsize; | ||
680 | unsigned vsize; | ||
681 | unsigned fps; | ||
682 | |||
683 | hsize = bt->hfrontporch + bt->hsync + bt->hbackporch + bt->width; | ||
684 | vsize = bt->vfrontporch + bt->vsync + bt->vbackporch + | ||
685 | bt->il_vfrontporch + bt->il_vsync + bt->il_vbackporch + | ||
686 | bt->height; | ||
687 | fps = (unsigned)bt->pixelclock / (hsize * vsize); | ||
688 | if (bt->width != vid_info->width || | ||
689 | bt->height != vid_info->height || | ||
690 | bt->interlaced != interlaced || | ||
691 | (fps != vid_info->fps && fps + 1 != vid_info->fps)) | ||
692 | continue; | ||
693 | *timings = hdpvr_dv_timings[i]; | ||
694 | break; | ||
695 | } | ||
696 | if (i == ARRAY_SIZE(hdpvr_dv_timings)) | ||
697 | ret = -ERANGE; | ||
698 | kfree(vid_info); | ||
699 | return ret; | ||
700 | } | ||
701 | |||
702 | static int vidioc_enum_dv_timings(struct file *file, void *_fh, | ||
703 | struct v4l2_enum_dv_timings *timings) | ||
704 | { | ||
705 | struct hdpvr_device *dev = video_drvdata(file); | ||
706 | struct hdpvr_fh *fh = _fh; | ||
707 | |||
708 | fh->legacy_mode = false; | ||
709 | memset(timings->reserved, 0, sizeof(timings->reserved)); | ||
710 | if (dev->options.video_input) | ||
711 | return -ENODATA; | ||
712 | if (timings->index >= ARRAY_SIZE(hdpvr_dv_timings)) | ||
713 | return -EINVAL; | ||
714 | timings->timings = hdpvr_dv_timings[timings->index]; | ||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | static int vidioc_dv_timings_cap(struct file *file, void *_fh, | ||
719 | struct v4l2_dv_timings_cap *cap) | ||
720 | { | ||
721 | struct hdpvr_device *dev = video_drvdata(file); | ||
722 | struct hdpvr_fh *fh = _fh; | ||
723 | |||
724 | fh->legacy_mode = false; | ||
725 | if (dev->options.video_input) | ||
726 | return -ENODATA; | ||
727 | cap->type = V4L2_DV_BT_656_1120; | ||
728 | cap->bt.min_width = 720; | ||
729 | cap->bt.max_width = 1920; | ||
730 | cap->bt.min_height = 480; | ||
731 | cap->bt.max_height = 1080; | ||
732 | cap->bt.min_pixelclock = 27000000; | ||
733 | cap->bt.max_pixelclock = 74250000; | ||
734 | cap->bt.standards = V4L2_DV_BT_STD_CEA861; | ||
735 | cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE; | ||
736 | return 0; | ||
737 | } | ||
738 | |||
597 | static const char *iname[] = { | 739 | static const char *iname[] = { |
598 | [HDPVR_COMPONENT] = "Component", | 740 | [HDPVR_COMPONENT] = "Component", |
599 | [HDPVR_SVIDEO] = "S-Video", | 741 | [HDPVR_SVIDEO] = "S-Video", |
@@ -827,29 +969,48 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, | |||
827 | return 0; | 969 | return 0; |
828 | } | 970 | } |
829 | 971 | ||
830 | static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data, | 972 | static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh, |
831 | struct v4l2_format *f) | 973 | struct v4l2_format *f) |
832 | { | 974 | { |
833 | struct hdpvr_device *dev = video_drvdata(file); | 975 | struct hdpvr_device *dev = video_drvdata(file); |
834 | struct hdpvr_video_info *vid_info; | 976 | struct hdpvr_fh *fh = _fh; |
835 | 977 | ||
836 | if (!dev) | 978 | /* |
837 | return -ENODEV; | 979 | * The original driver would always returns the current detected |
838 | 980 | * resolution as the format (and EFAULT if it couldn't be detected). | |
839 | vid_info = get_video_info(dev); | 981 | * With the introduction of VIDIOC_QUERY_DV_TIMINGS there is now a |
840 | if (!vid_info) | 982 | * better way of doing this, but to stay compatible with existing |
841 | return -EFAULT; | 983 | * applications we assume legacy mode every time an application opens |
842 | 984 | * the device. Only if one of the new DV_TIMINGS ioctls is called | |
843 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 985 | * will the filehandle go into 'normal' mode where g_fmt returns the |
986 | * last set format. | ||
987 | */ | ||
988 | if (fh->legacy_mode) { | ||
989 | struct hdpvr_video_info *vid_info; | ||
990 | |||
991 | vid_info = get_video_info(dev); | ||
992 | if (!vid_info) | ||
993 | return -EFAULT; | ||
994 | f->fmt.pix.width = vid_info->width; | ||
995 | f->fmt.pix.height = vid_info->height; | ||
996 | kfree(vid_info); | ||
997 | } else { | ||
998 | f->fmt.pix.width = dev->width; | ||
999 | f->fmt.pix.height = dev->height; | ||
1000 | } | ||
844 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | 1001 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; |
845 | f->fmt.pix.width = vid_info->width; | ||
846 | f->fmt.pix.height = vid_info->height; | ||
847 | f->fmt.pix.sizeimage = dev->bulk_in_size; | 1002 | f->fmt.pix.sizeimage = dev->bulk_in_size; |
848 | f->fmt.pix.colorspace = 0; | ||
849 | f->fmt.pix.bytesperline = 0; | 1003 | f->fmt.pix.bytesperline = 0; |
850 | f->fmt.pix.field = V4L2_FIELD_ANY; | 1004 | f->fmt.pix.priv = 0; |
851 | 1005 | if (f->fmt.pix.width == 720) { | |
852 | kfree(vid_info); | 1006 | /* SDTV formats */ |
1007 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
1008 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
1009 | } else { | ||
1010 | /* HDTV formats */ | ||
1011 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE240M; | ||
1012 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
1013 | } | ||
853 | return 0; | 1014 | return 0; |
854 | } | 1015 | } |
855 | 1016 | ||
@@ -916,6 +1077,11 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = { | |||
916 | .vidioc_s_std = vidioc_s_std, | 1077 | .vidioc_s_std = vidioc_s_std, |
917 | .vidioc_g_std = vidioc_g_std, | 1078 | .vidioc_g_std = vidioc_g_std, |
918 | .vidioc_querystd = vidioc_querystd, | 1079 | .vidioc_querystd = vidioc_querystd, |
1080 | .vidioc_s_dv_timings = vidioc_s_dv_timings, | ||
1081 | .vidioc_g_dv_timings = vidioc_g_dv_timings, | ||
1082 | .vidioc_query_dv_timings= vidioc_query_dv_timings, | ||
1083 | .vidioc_enum_dv_timings = vidioc_enum_dv_timings, | ||
1084 | .vidioc_dv_timings_cap = vidioc_dv_timings_cap, | ||
919 | .vidioc_enum_input = vidioc_enum_input, | 1085 | .vidioc_enum_input = vidioc_enum_input, |
920 | .vidioc_g_input = vidioc_g_input, | 1086 | .vidioc_g_input = vidioc_g_input, |
921 | .vidioc_s_input = vidioc_s_input, | 1087 | .vidioc_s_input = vidioc_s_input, |
@@ -924,6 +1090,8 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = { | |||
924 | .vidioc_s_audio = vidioc_s_audio, | 1090 | .vidioc_s_audio = vidioc_s_audio, |
925 | .vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap, | 1091 | .vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap, |
926 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | 1092 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, |
1093 | .vidioc_s_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
1094 | .vidioc_try_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
927 | .vidioc_encoder_cmd = vidioc_encoder_cmd, | 1095 | .vidioc_encoder_cmd = vidioc_encoder_cmd, |
928 | .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, | 1096 | .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, |
929 | .vidioc_log_status = v4l2_ctrl_log_status, | 1097 | .vidioc_log_status = v4l2_ctrl_log_status, |
@@ -975,6 +1143,7 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, | |||
975 | dev->cur_std = V4L2_STD_525_60; | 1143 | dev->cur_std = V4L2_STD_525_60; |
976 | dev->width = 720; | 1144 | dev->width = 720; |
977 | dev->height = 480; | 1145 | dev->height = 480; |
1146 | dev->cur_dv_timings = hdpvr_dv_timings[HDPVR_DEF_DV_TIMINGS_IDX]; | ||
978 | v4l2_ctrl_handler_init(hdl, 11); | 1147 | v4l2_ctrl_handler_init(hdl, 11); |
979 | if (dev->fw_ver > 0x15) { | 1148 | if (dev->fw_ver > 0x15) { |
980 | v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, | 1149 | v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, |
diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h index 050c6b9fec53..1478f3d57630 100644 --- a/drivers/media/usb/hdpvr/hdpvr.h +++ b/drivers/media/usb/hdpvr/hdpvr.h | |||
@@ -92,6 +92,7 @@ struct hdpvr_device { | |||
92 | /* holds the current set options */ | 92 | /* holds the current set options */ |
93 | struct hdpvr_options options; | 93 | struct hdpvr_options options; |
94 | v4l2_std_id cur_std; | 94 | v4l2_std_id cur_std; |
95 | struct v4l2_dv_timings cur_dv_timings; | ||
95 | 96 | ||
96 | uint flags; | 97 | uint flags; |
97 | 98 | ||