mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-20 20:47:25 +07:00
[media] hdpvr: add dv_timings support
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
8f69da9558
commit
3315c59a45
@ -21,6 +21,7 @@
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/v4l2-dv-timings.h>
|
||||
#include <media/v4l2-dev.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
@ -36,6 +37,25 @@
|
||||
list_size(&dev->free_buff_list), \
|
||||
list_size(&dev->rec_buff_list)); }
|
||||
|
||||
static const struct v4l2_dv_timings hdpvr_dv_timings[] = {
|
||||
V4L2_DV_BT_CEA_720X480I59_94,
|
||||
V4L2_DV_BT_CEA_720X576I50,
|
||||
V4L2_DV_BT_CEA_720X480P59_94,
|
||||
V4L2_DV_BT_CEA_720X576P50,
|
||||
V4L2_DV_BT_CEA_1280X720P50,
|
||||
V4L2_DV_BT_CEA_1280X720P60,
|
||||
V4L2_DV_BT_CEA_1920X1080I50,
|
||||
V4L2_DV_BT_CEA_1920X1080I60,
|
||||
};
|
||||
|
||||
/* Use 480i59 as the default timings */
|
||||
#define HDPVR_DEF_DV_TIMINGS_IDX (0)
|
||||
|
||||
struct hdpvr_fh {
|
||||
struct v4l2_fh fh;
|
||||
bool legacy_mode;
|
||||
};
|
||||
|
||||
static uint list_size(struct list_head *list)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
@ -355,13 +375,23 @@ static int hdpvr_stop_streaming(struct hdpvr_device *dev)
|
||||
* video 4 linux 2 file operations
|
||||
*/
|
||||
|
||||
static int hdpvr_open(struct file *file)
|
||||
{
|
||||
struct hdpvr_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL);
|
||||
|
||||
if (fh == NULL)
|
||||
return -ENOMEM;
|
||||
fh->legacy_mode = true;
|
||||
v4l2_fh_init(&fh->fh, video_devdata(file));
|
||||
v4l2_fh_add(&fh->fh);
|
||||
file->private_data = fh;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdpvr_release(struct file *file)
|
||||
{
|
||||
struct hdpvr_device *dev = video_drvdata(file);
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&dev->io_mutex);
|
||||
if (file->private_data == dev->owner) {
|
||||
hdpvr_stop_streaming(dev);
|
||||
@ -388,9 +418,6 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
|
||||
if (*pos)
|
||||
return -ESPIPE;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&dev->io_mutex);
|
||||
if (dev->status == STATUS_IDLE) {
|
||||
if (hdpvr_start_streaming(dev)) {
|
||||
@ -518,7 +545,7 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
|
||||
|
||||
static const struct v4l2_file_operations hdpvr_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = v4l2_fh_open,
|
||||
.open = hdpvr_open,
|
||||
.release = hdpvr_release,
|
||||
.read = hdpvr_read,
|
||||
.poll = hdpvr_poll,
|
||||
@ -594,6 +621,121 @@ static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *a)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_dv_timings(struct file *file, void *_fh,
|
||||
struct v4l2_dv_timings *timings)
|
||||
{
|
||||
struct hdpvr_device *dev = video_drvdata(file);
|
||||
struct hdpvr_fh *fh = _fh;
|
||||
int i;
|
||||
|
||||
fh->legacy_mode = false;
|
||||
if (dev->options.video_input)
|
||||
return -ENODATA;
|
||||
if (dev->status != STATUS_IDLE)
|
||||
return -EBUSY;
|
||||
for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++)
|
||||
if (v4l_match_dv_timings(timings, hdpvr_dv_timings + i, 0))
|
||||
break;
|
||||
if (i == ARRAY_SIZE(hdpvr_dv_timings))
|
||||
return -EINVAL;
|
||||
dev->cur_dv_timings = hdpvr_dv_timings[i];
|
||||
dev->width = hdpvr_dv_timings[i].bt.width;
|
||||
dev->height = hdpvr_dv_timings[i].bt.height;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_dv_timings(struct file *file, void *_fh,
|
||||
struct v4l2_dv_timings *timings)
|
||||
{
|
||||
struct hdpvr_device *dev = video_drvdata(file);
|
||||
struct hdpvr_fh *fh = _fh;
|
||||
|
||||
fh->legacy_mode = false;
|
||||
if (dev->options.video_input)
|
||||
return -ENODATA;
|
||||
*timings = dev->cur_dv_timings;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_query_dv_timings(struct file *file, void *_fh,
|
||||
struct v4l2_dv_timings *timings)
|
||||
{
|
||||
struct hdpvr_device *dev = video_drvdata(file);
|
||||
struct hdpvr_fh *fh = _fh;
|
||||
struct hdpvr_video_info *vid_info;
|
||||
bool interlaced;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
fh->legacy_mode = false;
|
||||
if (dev->options.video_input)
|
||||
return -ENODATA;
|
||||
vid_info = get_video_info(dev);
|
||||
if (vid_info == NULL)
|
||||
return -ENOLCK;
|
||||
interlaced = vid_info->fps <= 30;
|
||||
for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) {
|
||||
const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt;
|
||||
unsigned hsize;
|
||||
unsigned vsize;
|
||||
unsigned fps;
|
||||
|
||||
hsize = bt->hfrontporch + bt->hsync + bt->hbackporch + bt->width;
|
||||
vsize = bt->vfrontporch + bt->vsync + bt->vbackporch +
|
||||
bt->il_vfrontporch + bt->il_vsync + bt->il_vbackporch +
|
||||
bt->height;
|
||||
fps = (unsigned)bt->pixelclock / (hsize * vsize);
|
||||
if (bt->width != vid_info->width ||
|
||||
bt->height != vid_info->height ||
|
||||
bt->interlaced != interlaced ||
|
||||
(fps != vid_info->fps && fps + 1 != vid_info->fps))
|
||||
continue;
|
||||
*timings = hdpvr_dv_timings[i];
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(hdpvr_dv_timings))
|
||||
ret = -ERANGE;
|
||||
kfree(vid_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vidioc_enum_dv_timings(struct file *file, void *_fh,
|
||||
struct v4l2_enum_dv_timings *timings)
|
||||
{
|
||||
struct hdpvr_device *dev = video_drvdata(file);
|
||||
struct hdpvr_fh *fh = _fh;
|
||||
|
||||
fh->legacy_mode = false;
|
||||
memset(timings->reserved, 0, sizeof(timings->reserved));
|
||||
if (dev->options.video_input)
|
||||
return -ENODATA;
|
||||
if (timings->index >= ARRAY_SIZE(hdpvr_dv_timings))
|
||||
return -EINVAL;
|
||||
timings->timings = hdpvr_dv_timings[timings->index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_dv_timings_cap(struct file *file, void *_fh,
|
||||
struct v4l2_dv_timings_cap *cap)
|
||||
{
|
||||
struct hdpvr_device *dev = video_drvdata(file);
|
||||
struct hdpvr_fh *fh = _fh;
|
||||
|
||||
fh->legacy_mode = false;
|
||||
if (dev->options.video_input)
|
||||
return -ENODATA;
|
||||
cap->type = V4L2_DV_BT_656_1120;
|
||||
cap->bt.min_width = 720;
|
||||
cap->bt.max_width = 1920;
|
||||
cap->bt.min_height = 480;
|
||||
cap->bt.max_height = 1080;
|
||||
cap->bt.min_pixelclock = 27000000;
|
||||
cap->bt.max_pixelclock = 74250000;
|
||||
cap->bt.standards = V4L2_DV_BT_STD_CEA861;
|
||||
cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *iname[] = {
|
||||
[HDPVR_COMPONENT] = "Component",
|
||||
[HDPVR_SVIDEO] = "S-Video",
|
||||
@ -827,29 +969,48 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data,
|
||||
static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct hdpvr_device *dev = video_drvdata(file);
|
||||
struct hdpvr_video_info *vid_info;
|
||||
struct hdpvr_fh *fh = _fh;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
/*
|
||||
* The original driver would always returns the current detected
|
||||
* resolution as the format (and EFAULT if it couldn't be detected).
|
||||
* With the introduction of VIDIOC_QUERY_DV_TIMINGS there is now a
|
||||
* better way of doing this, but to stay compatible with existing
|
||||
* applications we assume legacy mode every time an application opens
|
||||
* the device. Only if one of the new DV_TIMINGS ioctls is called
|
||||
* will the filehandle go into 'normal' mode where g_fmt returns the
|
||||
* last set format.
|
||||
*/
|
||||
if (fh->legacy_mode) {
|
||||
struct hdpvr_video_info *vid_info;
|
||||
|
||||
vid_info = get_video_info(dev);
|
||||
if (!vid_info)
|
||||
return -EFAULT;
|
||||
|
||||
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
vid_info = get_video_info(dev);
|
||||
if (!vid_info)
|
||||
return -EFAULT;
|
||||
f->fmt.pix.width = vid_info->width;
|
||||
f->fmt.pix.height = vid_info->height;
|
||||
kfree(vid_info);
|
||||
} else {
|
||||
f->fmt.pix.width = dev->width;
|
||||
f->fmt.pix.height = dev->height;
|
||||
}
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
|
||||
f->fmt.pix.width = vid_info->width;
|
||||
f->fmt.pix.height = vid_info->height;
|
||||
f->fmt.pix.sizeimage = dev->bulk_in_size;
|
||||
f->fmt.pix.colorspace = 0;
|
||||
f->fmt.pix.bytesperline = 0;
|
||||
f->fmt.pix.field = V4L2_FIELD_ANY;
|
||||
|
||||
kfree(vid_info);
|
||||
f->fmt.pix.priv = 0;
|
||||
if (f->fmt.pix.width == 720) {
|
||||
/* SDTV formats */
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
|
||||
} else {
|
||||
/* HDTV formats */
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE240M;
|
||||
f->fmt.pix.field = V4L2_FIELD_NONE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -916,6 +1077,11 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
|
||||
.vidioc_s_std = vidioc_s_std,
|
||||
.vidioc_g_std = vidioc_g_std,
|
||||
.vidioc_querystd = vidioc_querystd,
|
||||
.vidioc_s_dv_timings = vidioc_s_dv_timings,
|
||||
.vidioc_g_dv_timings = vidioc_g_dv_timings,
|
||||
.vidioc_query_dv_timings= vidioc_query_dv_timings,
|
||||
.vidioc_enum_dv_timings = vidioc_enum_dv_timings,
|
||||
.vidioc_dv_timings_cap = vidioc_dv_timings_cap,
|
||||
.vidioc_enum_input = vidioc_enum_input,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
@ -924,6 +1090,8 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap,
|
||||
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
|
||||
.vidioc_s_fmt_vid_cap = vidioc_g_fmt_vid_cap,
|
||||
.vidioc_try_fmt_vid_cap = vidioc_g_fmt_vid_cap,
|
||||
.vidioc_encoder_cmd = vidioc_encoder_cmd,
|
||||
.vidioc_try_encoder_cmd = vidioc_try_encoder_cmd,
|
||||
.vidioc_log_status = v4l2_ctrl_log_status,
|
||||
@ -975,6 +1143,7 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
|
||||
dev->cur_std = V4L2_STD_525_60;
|
||||
dev->width = 720;
|
||||
dev->height = 480;
|
||||
dev->cur_dv_timings = hdpvr_dv_timings[HDPVR_DEF_DV_TIMINGS_IDX];
|
||||
v4l2_ctrl_handler_init(hdl, 11);
|
||||
if (dev->fw_ver > 0x15) {
|
||||
v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
|
||||
|
@ -92,6 +92,7 @@ struct hdpvr_device {
|
||||
/* holds the current set options */
|
||||
struct hdpvr_options options;
|
||||
v4l2_std_id cur_std;
|
||||
struct v4l2_dv_timings cur_dv_timings;
|
||||
|
||||
uint flags;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user