| Index: drivers/media/video/samsung/tv20/s5p_tv_v4l2.c
|
| diff --git a/drivers/media/video/samsung/tv20/s5p_tv_v4l2.c b/drivers/media/video/samsung/tv20/s5p_tv_v4l2.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..938dced7f6af466e9ed0f29270fc008e3ee40683
|
| --- /dev/null
|
| +++ b/drivers/media/video/samsung/tv20/s5p_tv_v4l2.c
|
| @@ -0,0 +1,1637 @@
|
| +/* linux/drivers/media/video/samsung/tv20/s5p_tv_v4l2.c
|
| +*
|
| +* Copyright (c) 2010 Samsung Electronics Co., Ltd.
|
| +* http://www.samsung.com/
|
| +*
|
| +* S5PV210 - Video4Linux API ftn. file for Samsung TVOut driver
|
| +*
|
| +* This program is free software; you can redistribute it and/or modify
|
| +* it under the terms of the GNU General Public License version 2 as
|
| +* published by the Free Software Foundation.
|
| +*/
|
| +
|
| +#include <linux/module.h>
|
| +#include <linux/kernel.h>
|
| +#include <linux/stddef.h>
|
| +#include <linux/string.h>
|
| +#include <linux/version.h>
|
| +
|
| +#include <media/v4l2-common.h>
|
| +#include <media/v4l2-ioctl.h>
|
| +
|
| +#include <linux/io.h>
|
| +#include <linux/uaccess.h>
|
| +
|
| +#include "s5p_tv.h"
|
| +
|
| +#ifdef CONFIG_TVOUT_DBG
|
| +#define S5P_V4L2_DEBUG 1
|
| +#endif
|
| +
|
| +#ifdef S5P_V4L2_DEBUG
|
| +#define V4L2PRINTK(fmt, args...) \
|
| + printk(KERN_INFO "[V4L2_IF] %s: " fmt, __func__ , ## args)
|
| +#else
|
| +#define V4L2PRINTK(fmt, args...)
|
| +#endif
|
| +
|
| +u8 hdcp_protocol_status;
|
| + /* 0 - hdcp stopped, 1 - hdcp started, 2 - hdcp reset */
|
| +
|
| +#define CVBS_S_VIDEO (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP|\
|
| + V4L2_STD_PAL|V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|\
|
| + V4L2_STD_PAL_60|V4L2_STD_NTSC_443)
|
| +
|
| +struct v4l2_output s5p_tv_outputs[] = {
|
| + {
|
| + .index = 0,
|
| + .name = "Analog COMPOSITE",
|
| + .type = V4L2_OUTPUT_TYPE_COMPOSITE,
|
| + .audioset = 0,
|
| + .modulator = 0,
|
| + .std = CVBS_S_VIDEO,
|
| + }, {
|
| + .index = 1,
|
| + .name = "Analog SVIDEO",
|
| + .type = V4L2_OUTPUT_TYPE_SVIDEO,
|
| + .audioset = 0,
|
| + .modulator = 0,
|
| + .std = CVBS_S_VIDEO,
|
| + }, {
|
| + .index = 2,
|
| + .name = "Analog COMPONENT_YPBPR_I",
|
| + .type = V4L2_OUTPUT_TYPE_YPBPR_INERLACED,
|
| + .audioset = 0,
|
| + .modulator = 0,
|
| + .std = V4L2_STD_ALL,
|
| + }, {
|
| + .index = 3,
|
| + .name = "Analog COMPONENT_YPBPR_P",
|
| + .type = V4L2_OUTPUT_TYPE_YPBPR_PROGRESSIVE,
|
| + .audioset = 0,
|
| + .modulator = 0,
|
| + .std = V4L2_STD_ALL,
|
| + }, {
|
| + .index = 4,
|
| + .name = "Analog COMPONENT_RGB_P",
|
| + .type = V4L2_OUTPUT_TYPE_RGB_PROGRESSIVE,
|
| + .audioset = 0,
|
| + .modulator = 0,
|
| + .std = V4L2_STD_ALL,
|
| + }, {
|
| + .index = 5,
|
| + .name = "Digital HDMI(YCbCr)",
|
| + .type = V4L2_OUTPUT_TYPE_HDMI,
|
| + .audioset = 2,
|
| + .modulator = 0,
|
| + .std =
|
| + V4L2_STD_480P_60_16_9 | V4L2_STD_480P_60_16_9 |
|
| + V4L2_STD_720P_60 | V4L2_STD_720P_50
|
| + | V4L2_STD_1080P_60 | V4L2_STD_1080P_50 |
|
| + V4L2_STD_1080I_60 | V4L2_STD_1080I_50 |
|
| + V4L2_STD_480P_59 | V4L2_STD_720P_59 |
|
| + V4L2_STD_1080I_59 | V4L2_STD_1080P_59 |
|
| + V4L2_STD_1080P_30,
|
| + }, {
|
| + .index = 6,
|
| + .name = "Digital HDMI(RGB)",
|
| + .type = V4L2_OUTPUT_TYPE_HDMI_RGB,
|
| + .audioset = 2,
|
| + .modulator = 0,
|
| + .std = V4L2_STD_480P_60_16_9 |
|
| + V4L2_STD_480P_60_16_9 |
|
| + V4L2_STD_720P_60 | V4L2_STD_720P_50
|
| + | V4L2_STD_1080P_60 | V4L2_STD_1080P_50 |
|
| + V4L2_STD_1080I_60 | V4L2_STD_1080I_50 |
|
| + V4L2_STD_480P_59 | V4L2_STD_720P_59 |
|
| + V4L2_STD_1080I_59 | V4L2_STD_1080P_59 |
|
| + V4L2_STD_1080P_30,
|
| + }, {
|
| + .index = 7,
|
| + .name = "Digital DVI",
|
| + .type = V4L2_OUTPUT_TYPE_DVI,
|
| + .audioset = 2,
|
| + .modulator = 0,
|
| + .std =
|
| + V4L2_STD_480P_60_16_9 | V4L2_STD_480P_60_16_9 |
|
| + V4L2_STD_720P_60 | V4L2_STD_720P_50
|
| + | V4L2_STD_1080P_60 | V4L2_STD_1080P_50 |
|
| + V4L2_STD_1080I_60 | V4L2_STD_1080I_50 |
|
| + V4L2_STD_480P_59 | V4L2_STD_720P_59 |
|
| + V4L2_STD_1080I_59 | V4L2_STD_1080P_59 |
|
| + V4L2_STD_1080P_30,
|
| + }
|
| +
|
| +};
|
| +
|
| +const struct v4l2_fmtdesc s5p_tv_o_fmt_desc[] = {
|
| + {
|
| + .index = 0,
|
| + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
|
| + .description = "YUV420, NV12 (Video Processor)",
|
| + .pixelformat = V4L2_PIX_FMT_NV12,
|
| + .flags = FORMAT_FLAGS_CrCb,
|
| + }
|
| +};
|
| +
|
| +const struct v4l2_fmtdesc s5p_tv_o_overlay_fmt_desc[] = {
|
| + {
|
| + .index = 0,
|
| + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY,
|
| + .description = "16bpp RGB, le - RGB[565]",
|
| + .pixelformat = V4L2_PIX_FMT_RGB565,
|
| + .flags = FORMAT_FLAGS_PACKED,
|
| + }, {
|
| + .index = 1,
|
| + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY,
|
| + .description = "16bpp RGB, le - ARGB[1555]",
|
| + .pixelformat = V4L2_PIX_FMT_RGB555,
|
| + .flags = FORMAT_FLAGS_PACKED,
|
| + }, {
|
| + .index = 2,
|
| + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY,
|
| + .description = "16bpp RGB, le - ARGB[4444]",
|
| + .pixelformat = V4L2_PIX_FMT_RGB444,
|
| + .flags = FORMAT_FLAGS_PACKED,
|
| + }, {
|
| + .index = 3,
|
| + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY,
|
| + .description = "32bpp RGB, le - ARGB[8888]",
|
| + .pixelformat = V4L2_PIX_FMT_RGB32,
|
| + .flags = FORMAT_FLAGS_PACKED,
|
| + }
|
| +};
|
| +
|
| +const struct v4l2_standard s5p_tv_standards[] = {
|
| + {
|
| + .index = 0,
|
| + .id = V4L2_STD_NTSC_M,
|
| + .name = "NTSC_M",
|
| + }, {
|
| +
|
| + .index = 1,
|
| + .id = V4L2_STD_PAL_BDGHI,
|
| + .name = "PAL_BDGHI",
|
| + }, {
|
| + .index = 2,
|
| + .id = V4L2_STD_PAL_M,
|
| + .name = "PAL_M",
|
| + }, {
|
| + .index = 3,
|
| + .id = V4L2_STD_PAL_N,
|
| + .name = "PAL_N",
|
| + }, {
|
| + .index = 4,
|
| + .id = V4L2_STD_PAL_Nc,
|
| + .name = "PAL_Nc",
|
| + }, {
|
| + .index = 5,
|
| + .id = V4L2_STD_PAL_60,
|
| + .name = "PAL_60",
|
| + }, {
|
| + .index = 6,
|
| + .id = V4L2_STD_NTSC_443,
|
| + .name = "NTSC_443",
|
| + }, {
|
| + .index = 7,
|
| + .id = V4L2_STD_480P_60_16_9,
|
| + .name = "480P_60_16_9",
|
| + }, {
|
| + .index = 8,
|
| + .id = V4L2_STD_480P_60_4_3,
|
| + .name = "480P_60_4_3",
|
| + }, {
|
| + .index = 9,
|
| + .id = V4L2_STD_576P_50_16_9,
|
| + .name = "576P_50_16_9",
|
| + }, {
|
| + .index = 10,
|
| + .id = V4L2_STD_576P_50_4_3,
|
| + .name = "576P_50_4_3",
|
| + }, {
|
| + .index = 11,
|
| + .id = V4L2_STD_720P_60,
|
| + .name = "720P_60",
|
| + }, {
|
| + .index = 12,
|
| + .id = V4L2_STD_720P_50,
|
| + .name = "720P_50",
|
| + },
|
| + {
|
| + .index = 13,
|
| + .id = V4L2_STD_1080P_60,
|
| + .name = "1080P_60",
|
| + }, {
|
| + .index = 14,
|
| + .id = V4L2_STD_1080P_50,
|
| + .name = "1080P_50",
|
| + }, {
|
| + .index = 15,
|
| + .id = V4L2_STD_1080I_60,
|
| + .name = "1080I_60",
|
| + }, {
|
| + .index = 16,
|
| + .id = V4L2_STD_1080I_50,
|
| + .name = "1080I_50",
|
| + }, {
|
| + .index = 17,
|
| + .id = V4L2_STD_480P_59,
|
| + .name = "480P_59",
|
| + }, {
|
| + .index = 18,
|
| + .id = V4L2_STD_720P_59,
|
| + .name = "720P_59",
|
| + }, {
|
| + .index = 19,
|
| + .id = V4L2_STD_1080I_59,
|
| + .name = "1080I_59",
|
| + }, {
|
| + .index = 20,
|
| + .id = V4L2_STD_1080P_59,
|
| + .name = "1080I_50",
|
| + }, {
|
| + .index = 21,
|
| + .id = V4L2_STD_1080P_30,
|
| + .name = "1080I_30",
|
| + }
|
| +};
|
| +
|
| +/* TODO: set default format for v, vo0/1 */
|
| +
|
| +const struct v4l2_format s5p_tv_format[] = {
|
| + {
|
| + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
|
| + }, {
|
| + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY,
|
| + }, {
|
| + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY,
|
| + },
|
| +};
|
| +
|
| +#define S5P_TVOUT_MAX_STANDARDS ARRAY_SIZE(s5p_tv_standards)
|
| +#define S5P_TVOUT_MAX_O_TYPES ARRAY_SIZE(s5p_tv_outputs)
|
| +#define S5P_TVOUT_MAX_O_FMT ARRAY_SIZE(s5p_tv_format)
|
| +#define S5P_TVOUT_MAX_O_FMT_DESC ARRAY_SIZE(s5p_tv_o_fmt_desc)
|
| +#define S5P_TVOUT_MAX_O_OVERLAY_FMT_DESC \
|
| + ARRAY_SIZE(s5p_tv_o_overlay_fmt_desc)
|
| +
|
| +
|
| +void s5p_tv_v4l2_init_param(void)
|
| +{
|
| + s5ptv_status.v4l2.output =
|
| + (struct v4l2_output *)&s5p_tv_outputs[0];
|
| + s5ptv_status.v4l2.std =
|
| + (struct v4l2_standard *)&s5p_tv_standards[0];
|
| + s5ptv_status.v4l2.fmt_v =
|
| + (struct v4l2_format *)&s5p_tv_o_fmt_desc[0];
|
| + s5ptv_status.v4l2.fmt_vo_0 =
|
| + (struct v4l2_format *)&s5p_tv_format[1];
|
| + s5ptv_status.v4l2.fmt_vo_1 =
|
| + (struct v4l2_format *)&s5p_tv_format[2];
|
| + s5ptv_status.hdmi_audio_type = HDMI_AUDIO_PCM;
|
| +}
|
| +
|
| +/* VIDIOC_QUERYCAP handler */
|
| +static int s5p_tv_v4l2_querycap(
|
| + struct file *file, void *fh, struct v4l2_capability *cap)
|
| +{
|
| + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh;
|
| + u32 index;
|
| +
|
| + if (layer == NULL) {
|
| + index = 0;
|
| + strcpy(cap->driver, "S3C TV Vid drv");
|
| + cap->capabilities = V4L2_CAP_VIDEO_OUTPUT;
|
| + } else {
|
| + index = layer->index + 1;
|
| + strcpy(cap->driver, "S3C TV Grp drv");
|
| + cap->capabilities = V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
|
| + }
|
| +
|
| + strlcpy(cap->card,
|
| + s5ptv_status.video_dev[index]->name, sizeof(cap->card));
|
| +
|
| + sprintf(cap->bus_info, "ARM AHB BUS");
|
| + cap->version = KERNEL_VERSION(2, 6, 29);
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +
|
| +/* VIDIOC_ENUM_FMT handlers */
|
| +static int s5p_tv_v4l2_enum_fmt_vid_out(
|
| + struct file *file, void *fh, struct v4l2_fmtdesc *f)
|
| +{
|
| + int index = f->index;
|
| +
|
| + V4L2PRINTK("(%d)++\n", f->index);
|
| +
|
| + if (index >= S5P_TVOUT_MAX_O_FMT_DESC) {
|
| + V4L2PRINTK("exceeded S5P_TVOUT_MAX_O_FMT_DESC\n");
|
| + return -EINVAL;
|
| + }
|
| +
|
| + memcpy(f, &s5p_tv_o_fmt_desc[index],
|
| + sizeof(struct v4l2_fmtdesc));
|
| +
|
| + V4L2PRINTK("()--\n");
|
| + return 0;
|
| +
|
| +}
|
| +
|
| +static int s5p_tv_v4l2_enum_fmt_vid_out_overlay(
|
| + struct file *file, void *fh, struct v4l2_fmtdesc *f)
|
| +{
|
| + int index = f->index;
|
| +
|
| + V4L2PRINTK("(%d)++\n", f->index);
|
| +
|
| + if (index >= S5P_TVOUT_MAX_O_OVERLAY_FMT_DESC) {
|
| + V4L2PRINTK("exceeded S5P_TVOUT_MAX_O_OVERLAY_FMT_DESC\n");
|
| + return -EINVAL;
|
| + }
|
| +
|
| + memcpy(f, &s5p_tv_o_overlay_fmt_desc[index],
|
| + sizeof(struct v4l2_fmtdesc));
|
| +
|
| + V4L2PRINTK("()--\n");
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +
|
| +/* VIDIOC_G_FMT handlers */
|
| +static int s5p_tv_v4l2_g_fmt_vid_out(
|
| + struct file *file, void *fh, struct v4l2_format *f)
|
| +{
|
| +
|
| + struct v4l2_format *vid_out_fmt = f;
|
| +
|
| + V4L2PRINTK("(0x%08x)++\n", f->type);
|
| +
|
| + switch (vid_out_fmt->type) {
|
| +
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT: {
|
| +
|
| + struct v4l2_pix_format_s5p_tvout vparam;
|
| + memset(&vparam, 0, sizeof(struct v4l2_pix_format_s5p_tvout));
|
| +
|
| + vparam.base_y =
|
| + (void *)s5ptv_status.vl_basic_param.top_y_address;
|
| + vparam.base_c =
|
| + (void *)s5ptv_status.vl_basic_param.top_c_address;
|
| + vparam.pix_fmt.pixelformat =
|
| + s5ptv_status.src_color; /* VPROC_SRC_COLOR_NV12 */
|
| + vparam.pix_fmt.width =
|
| + s5ptv_status.vl_basic_param.src_width;
|
| + vparam.pix_fmt.height =
|
| + s5ptv_status.vl_basic_param.src_height;
|
| + V4L2PRINTK(
|
| + "[type0x%08x]:addr_y:[0x%08x],addr_c[0x%08x],w[%d],h[%d]\n",
|
| + f->type,
|
| + s5ptv_status.vl_basic_param.top_y_address,
|
| + s5ptv_status.vl_basic_param.top_c_address,
|
| + s5ptv_status.vl_basic_param.src_width,
|
| + s5ptv_status.vl_basic_param.src_height);
|
| + memcpy(vid_out_fmt->fmt.raw_data, &vparam,
|
| + sizeof(struct v4l2_pix_format_s5p_tvout));
|
| + break;
|
| + }
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +static int s5p_tv_v4l2_g_fmt_vid_out_overlay(
|
| + struct file *file, void *fh, struct v4l2_format *f)
|
| +{
|
| +
|
| + struct v4l2_format *vid_out_fmt = f;
|
| +
|
| + V4L2PRINTK("(0x%08x)++\n", f->type);
|
| +
|
| + switch (vid_out_fmt->type) {
|
| +
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
|
| +
|
| + struct v4l2_window_s5p_tvout vparam;
|
| + memset(&vparam, 0, sizeof(struct v4l2_window_s5p_tvout));
|
| +
|
| + if (s5ptv_status.vl_basic_param.win_blending) {
|
| + vparam.flags = V4L2_FBUF_FLAG_CHROMAKEY;
|
| + vparam.capability = V4L2_FBUF_CAP_CHROMAKEY;
|
| + }
|
| +
|
| + if (s5ptv_status.vl_basic_param.alpha) {
|
| + vparam.flags = V4L2_FBUF_FLAG_LOCAL_ALPHA;
|
| + vparam.capability = V4L2_FBUF_CAP_LOCAL_ALPHA;
|
| + }
|
| +
|
| + vparam.priority =
|
| + s5ptv_status.vl_basic_param.priority;
|
| +
|
| + vparam.win.w.left =
|
| + s5ptv_status.vl_basic_param.src_offset_x;
|
| + vparam.win.w.top =
|
| + s5ptv_status.vl_basic_param.src_offset_y;
|
| + vparam.win.w.width =
|
| + s5ptv_status.vl_basic_param.src_width;
|
| + vparam.win.w.height =
|
| + s5ptv_status.vl_basic_param.src_height;
|
| + V4L2PRINTK(
|
| + "[type 0x%08x] : left:[%d],top[%d],width[%d],height[%d]\n",
|
| + f->type,
|
| + s5ptv_status.vl_basic_param.src_offset_x,
|
| + s5ptv_status.vl_basic_param.src_offset_y,
|
| + s5ptv_status.vl_basic_param.src_width,
|
| + s5ptv_status.vl_basic_param.src_height);
|
| + memcpy(vid_out_fmt->fmt.raw_data,
|
| + &vparam, sizeof(struct v4l2_window_s5p_tvout));
|
| + break;
|
| + }
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + V4L2PRINTK("()--\n");
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +/* VIDIOC_S_FMT handlers */
|
| +static int s5p_tv_v4l2_s_fmt_vid_out(
|
| + struct file *file, void *fh, struct v4l2_format *f)
|
| +{
|
| +
|
| + struct v4l2_format *vid_out_fmt = f;
|
| +
|
| + V4L2PRINTK("(0x%08x)++\n", f->type);
|
| +
|
| + switch (vid_out_fmt->type) {
|
| +
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT: {
|
| +
|
| + struct v4l2_pix_format_s5p_tvout vparam;
|
| + memcpy(&vparam, vid_out_fmt->fmt.raw_data,
|
| + sizeof(struct v4l2_pix_format_s5p_tvout));
|
| +
|
| + s5ptv_status.vl_basic_param.src_width =
|
| + vparam.pix_fmt.width;
|
| + s5ptv_status.vl_basic_param.src_height =
|
| + vparam.pix_fmt.height;
|
| + s5ptv_status.src_color = vparam.pix_fmt.pixelformat;
|
| +
|
| + s5ptv_status.vl_basic_param.top_y_address =
|
| + (unsigned int)vparam.base_y;
|
| + s5ptv_status.vl_basic_param.top_c_address =
|
| + (unsigned int)vparam.base_c;
|
| +
|
| + /* check progressive or not */
|
| + if (vparam.pix_fmt.field == V4L2_FIELD_NONE) {
|
| +
|
| + /* progressive */
|
| +
|
| + switch (vparam.pix_fmt.pixelformat) {
|
| +
|
| + case V4L2_PIX_FMT_NV12:
|
| + /* linear */
|
| + s5ptv_status.src_color =
|
| + VPROC_SRC_COLOR_NV12;
|
| + break;
|
| + case V4L2_PIX_FMT_NV12T:
|
| + /* tiled */
|
| + s5ptv_status.src_color =
|
| + VPROC_SRC_COLOR_TILE_NV12;
|
| + break;
|
| + default:
|
| + V4L2PRINTK("src img format not supported\n");
|
| + break;
|
| + }
|
| +
|
| + s5ptv_status.field_id = VPROC_TOP_FIELD;
|
| +
|
| + if (s5ptv_status.vp_layer_enable) {
|
| + struct s5p_video_img_address temp_addr;
|
| + struct s5p_img_size img_size;
|
| +
|
| + temp_addr.y_address =
|
| + (unsigned int)vparam.base_y;
|
| + temp_addr.c_address =
|
| + (unsigned int)vparam.base_c;
|
| + img_size.img_width =
|
| + (unsigned int)vparam.pix_fmt.width;
|
| + img_size.img_height =
|
| + (unsigned int)vparam.pix_fmt.height;
|
| +
|
| + tv_vlayer_set_top_address(
|
| + (unsigned long)&temp_addr);
|
| + tv_vlayer_set_img_size(
|
| + (unsigned long)&img_size);
|
| + tv_vlayer_set_src_size(
|
| + (unsigned long)&img_size);
|
| +
|
| + }
|
| + } else if (vparam.pix_fmt.field == V4L2_FIELD_INTERLACED_TB) {
|
| +
|
| + /* interlaced */
|
| +
|
| + switch (vparam.pix_fmt.pixelformat) {
|
| +
|
| + case V4L2_PIX_FMT_NV12:
|
| + /* linear */
|
| + s5ptv_status.src_color = VPROC_SRC_COLOR_NV12IW;
|
| + break;
|
| + case V4L2_PIX_FMT_NV12T:
|
| + /* tiled */
|
| + s5ptv_status.src_color =
|
| + VPROC_SRC_COLOR_TILE_NV12IW;
|
| + break;
|
| + default:
|
| + V4L2PRINTK("src img format not supported\n");
|
| + break;
|
| + }
|
| +
|
| + if (vparam.pix_fmt.priv == V4L2_FIELD_BOTTOM)
|
| + s5ptv_status.field_id = VPROC_BOTTOM_FIELD;
|
| + else
|
| + s5ptv_status.field_id = VPROC_TOP_FIELD;
|
| +
|
| + if (s5ptv_status.vp_layer_enable) {
|
| + struct s5p_video_img_address temp_addr;
|
| + struct s5p_img_size img_size;
|
| +
|
| + temp_addr.y_address =
|
| + (unsigned int)vparam.base_y;
|
| + temp_addr.c_address =
|
| + (unsigned int)vparam.base_c;
|
| + img_size.img_width =
|
| + (unsigned int)vparam.pix_fmt.width;
|
| + img_size.img_height =
|
| + (unsigned int)vparam.pix_fmt.height;
|
| +
|
| + tv_vlayer_set_top_address(
|
| + (unsigned long)&temp_addr);
|
| + tv_vlayer_set_img_size(
|
| + (unsigned long)&img_size);
|
| + tv_vlayer_set_src_size(
|
| + (unsigned long)&img_size);
|
| +
|
| + }
|
| +
|
| + } else {
|
| + V4L2PRINTK("this field id not supported\n");
|
| + }
|
| + break;
|
| + }
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + V4L2PRINTK(
|
| + "[type 0x%08x] : addr_y:[0x%08x],addr_c[0x%08x],width[%d],height[%d]\n",
|
| + f->type,
|
| + s5ptv_status.vl_basic_param.top_y_address,
|
| + s5ptv_status.vl_basic_param.top_c_address,
|
| + s5ptv_status.vl_basic_param.src_width,
|
| + s5ptv_status.vl_basic_param.src_height);
|
| + V4L2PRINTK("()--\n");
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +
|
| +static int s5p_tv_v4l2_s_fmt_vid_out_overlay(
|
| + struct file *file, void *fh, struct v4l2_format *f)
|
| +{
|
| +
|
| + struct v4l2_format *vid_out_fmt = f;
|
| +
|
| + V4L2PRINTK("(0x%08x)++\n", f->type);
|
| +
|
| + switch (vid_out_fmt->type) {
|
| +
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
|
| +
|
| + struct v4l2_window_s5p_tvout vparam;
|
| + memcpy(&vparam, vid_out_fmt->fmt.raw_data,
|
| + sizeof(struct v4l2_window_s5p_tvout));
|
| +
|
| + s5ptv_status.vl_basic_param.win_blending =
|
| + (vparam.flags & V4L2_FBUF_FLAG_CHROMAKEY) ? 1 : 0;
|
| + s5ptv_status.vl_basic_param.alpha =
|
| + (vparam.flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) ? 1 : 0;
|
| + s5ptv_status.vl_basic_param.priority =
|
| + vparam.priority;
|
| + s5ptv_status.vl_basic_param.src_offset_x =
|
| + vparam.win.w.left;
|
| + s5ptv_status.vl_basic_param.src_offset_y =
|
| + vparam.win.w.top;
|
| + s5ptv_status.vl_basic_param.src_width = vparam.win.w.width;
|
| + s5ptv_status.vl_basic_param.src_height = vparam.win.w.height;
|
| + V4L2PRINTK(
|
| + "[type 0x%08x] : left: [%d],top [%d],width[%d],height[%d]\n",
|
| + f->type,
|
| + s5ptv_status.vl_basic_param.src_offset_x,
|
| + s5ptv_status.vl_basic_param.src_offset_y,
|
| + s5ptv_status.vl_basic_param.src_width,
|
| + s5ptv_status.vl_basic_param.src_height);
|
| +
|
| + if (s5ptv_status.vp_layer_enable) {
|
| + struct s5p_img_offset img_offset;
|
| + struct s5p_img_size img_size;
|
| +
|
| + img_offset.offset_x = vparam.win.w.left;
|
| + img_offset.offset_y = vparam.win.w.top;
|
| + img_size.img_width = vparam.win.w.width;
|
| + img_size.img_height = vparam.win.w.height;
|
| + tv_vlayer_set_blending(
|
| + s5ptv_status.vl_basic_param.win_blending);
|
| + tv_vlayer_set_alpha(
|
| + s5ptv_status.vl_basic_param.alpha);
|
| + tv_vlayer_set_priority(vparam.priority);
|
| + tv_vlayer_set_src_position(
|
| + (unsigned long)&img_offset);
|
| + tv_vlayer_set_src_size((unsigned long)&img_size);
|
| + }
|
| +
|
| + break;
|
| + }
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + V4L2PRINTK("()--\n");
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +/* start overlay * */
|
| +static int s5p_tv_v4l2_overlay(struct file *file, void *fh, unsigned int i)
|
| +{
|
| + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh;
|
| + int start = i;
|
| + V4L2PRINTK("(0x%08x)++\n", i);
|
| +
|
| + if (start)
|
| + tv_grp_start(layer->index);
|
| + else
|
| + tv_grp_stop(layer->index);
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +static int s5p_tv_v4l2_g_fbuf(
|
| + struct file *file, void *fh, struct v4l2_framebuffer *a)
|
| +{
|
| +
|
| + struct v4l2_framebuffer *fbuf = a;
|
| + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh;
|
| +
|
| + fbuf->base = (void *)s5ptv_overlay[layer->index].base_addr;
|
| + fbuf->fmt.pixelformat = s5ptv_overlay[layer->index].fb.fmt.pixelformat;
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +static int s5p_tv_v4l2_s_fbuf(
|
| + struct file *file, void *fh, struct v4l2_framebuffer *a)
|
| +{
|
| +
|
| + struct v4l2_framebuffer *fbuf = a;
|
| + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh;
|
| +
|
| + s5ptv_overlay[layer->index].base_addr = (unsigned int)fbuf->base;
|
| +
|
| + switch (fbuf->fmt.pixelformat) {
|
| +
|
| + case V4L2_PIX_FMT_RGB565:
|
| + s5ptv_overlay[layer->index].fb.fmt.pixelformat =
|
| + VM_DIRECT_RGB565;
|
| + break;
|
| +
|
| + case V4L2_PIX_FMT_RGB555:
|
| + s5ptv_overlay[layer->index].fb.fmt.pixelformat =
|
| + VM_DIRECT_RGB1555;
|
| + break;
|
| +
|
| + case V4L2_PIX_FMT_RGB444:
|
| + s5ptv_overlay[layer->index].fb.fmt.pixelformat =
|
| + VM_DIRECT_RGB4444;
|
| + break;
|
| +
|
| + case V4L2_PIX_FMT_RGB32:
|
| + s5ptv_overlay[layer->index].fb.fmt.pixelformat =
|
| + VM_DIRECT_RGB8888;
|
| + break;
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +/* Stream on/off */
|
| +static int s5p_tv_v4l2_streamon(
|
| + struct file *file, void *fh, enum v4l2_buf_type i)
|
| +{
|
| + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh;
|
| +
|
| + V4L2PRINTK("(0x%08x)++\n", i);
|
| +
|
| + switch (i) {
|
| +
|
| + /* Vlayer */
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
| + tv_vlayer_init_param(0);
|
| + tv_vlayer_start();
|
| + s5ptv_status.vp_layer_enable = true;
|
| + break;
|
| +
|
| + /* GRP0/1 */
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
| + tv_grp_start(layer->index);
|
| + break;
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + V4L2PRINTK("()--\n");
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +static int s5p_tv_v4l2_streamoff(
|
| + struct file *file, void *fh, enum v4l2_buf_type i)
|
| +{
|
| + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh;
|
| +
|
| + V4L2PRINTK("(0x%08x)++\n", i);
|
| +
|
| + switch (i) {
|
| +
|
| + /* Vlayer */
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
| + tv_vlayer_stop();
|
| + break;
|
| +
|
| + /* GRP0/1 */
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
| + tv_grp_stop(layer->index);
|
| + break;
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + V4L2PRINTK("()--\n");
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +/* Standard handling ENUMSTD is handled by videodev.c */
|
| +static int s5p_tv_v4l2_g_std(struct file *file, void *fh, v4l2_std_id *norm)
|
| +{
|
| + V4L2PRINTK("()++\n");
|
| +
|
| + *norm = s5ptv_status.v4l2.std->id;
|
| +
|
| + V4L2PRINTK("(%d)++\n", (int)(*norm));
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +static int s5p_tv_v4l2_s_std(struct file *file, void *fh, v4l2_std_id *norm)
|
| +{
|
| + unsigned int i = 0;
|
| + v4l2_std_id std_id = *norm;
|
| +
|
| + V4L2PRINTK("(0x%08Lx)++\n", std_id);
|
| +
|
| + s5ptv_status.v4l2.std = NULL;
|
| +
|
| + do {
|
| + if (s5p_tv_standards[i].id == std_id) {
|
| + s5ptv_status.v4l2.std =
|
| + (struct v4l2_standard *)&s5p_tv_standards[i];
|
| + break;
|
| + }
|
| +
|
| + i++;
|
| + } while (i < S5P_TVOUT_MAX_STANDARDS);
|
| +
|
| + if (i >= S5P_TVOUT_MAX_STANDARDS || s5ptv_status.v4l2.std == NULL) {
|
| + V4L2PRINTK(
|
| + "(ERR) There is no tv-out standards : index = 0x%08Lx\n",
|
| + std_id);
|
| + return -EINVAL;
|
| + }
|
| +
|
| + switch (std_id) {
|
| +
|
| + case V4L2_STD_NTSC_M:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_NTSC_M;
|
| + break;
|
| +
|
| + case V4L2_STD_PAL_BDGHI:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_PAL_BDGHI;
|
| + break;
|
| +
|
| + case V4L2_STD_PAL_M:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_PAL_M;
|
| + break;
|
| +
|
| + case V4L2_STD_PAL_N:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_PAL_N;
|
| + break;
|
| +
|
| + case V4L2_STD_PAL_Nc:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_PAL_NC;
|
| + break;
|
| +
|
| + case V4L2_STD_PAL_60:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_PAL_60;
|
| + break;
|
| +
|
| + case V4L2_STD_NTSC_443:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_NTSC_443;
|
| + break;
|
| +
|
| + case V4L2_STD_480P_60_16_9:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_480P_60_16_9;
|
| + break;
|
| +
|
| + case V4L2_STD_480P_60_4_3:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_480P_60_4_3;
|
| + break;
|
| +
|
| + case V4L2_STD_480P_59:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_480P_59;
|
| + break;
|
| +
|
| + case V4L2_STD_576P_50_16_9:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_576P_50_16_9;
|
| + break;
|
| +
|
| + case V4L2_STD_576P_50_4_3:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_576P_50_4_3;
|
| + break;
|
| +
|
| + case V4L2_STD_720P_60:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_720P_60;
|
| + break;
|
| +
|
| + case V4L2_STD_720P_59:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_720P_59;
|
| + break;
|
| +
|
| + case V4L2_STD_720P_50:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_720P_50;
|
| + break;
|
| +
|
| + case V4L2_STD_1080I_60:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_1080I_60;
|
| + break;
|
| +
|
| + case V4L2_STD_1080I_59:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_1080I_59;
|
| + break;
|
| +
|
| + case V4L2_STD_1080I_50:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_1080I_50;
|
| + break;
|
| +
|
| + case V4L2_STD_1080P_30:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_1080P_30;
|
| + break;
|
| +
|
| + case V4L2_STD_1080P_60:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_1080P_60;
|
| + break;
|
| +
|
| + case V4L2_STD_1080P_59:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_1080P_59;
|
| + break;
|
| +
|
| + case V4L2_STD_1080P_50:
|
| + s5ptv_status.tvout_param.disp_mode = TVOUT_1080P_50;
|
| + break;
|
| + default:
|
| + V4L2PRINTK(
|
| + "(ERR) not supported standard id : index = 0x%08Lx\n",
|
| + std_id);
|
| + return -EINVAL;
|
| + }
|
| +
|
| + V4L2PRINTK("()--\n");
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +/* Output handling */
|
| +static int s5p_tv_v4l2_enum_output(struct file *file,
|
| + void *fh, struct v4l2_output *a)
|
| +{
|
| + unsigned int index = a->index;
|
| + V4L2PRINTK("(%d)++\n", a->index);
|
| +
|
| + if (index >= S5P_TVOUT_MAX_O_TYPES) {
|
| + V4L2PRINTK("exceeded supported output!!\n");
|
| + return -EINVAL;
|
| + }
|
| +
|
| + memcpy(a, &s5p_tv_outputs[index], sizeof(struct v4l2_output));
|
| +
|
| + V4L2PRINTK("()--\n");
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +static int s5p_tv_v4l2_g_output(struct file *file, void *fh, unsigned int *i)
|
| +{
|
| + V4L2PRINTK("(%d)++\n", *i);
|
| +
|
| + *i = s5ptv_status.v4l2.output->index;
|
| +
|
| + V4L2PRINTK("()--\n");
|
| + return 0;
|
| +}
|
| +
|
| +static int s5p_tv_v4l2_s_output(struct file *file, void *fh, unsigned int i)
|
| +{
|
| + V4L2PRINTK("(%d)++\n", i);
|
| +
|
| + if (i >= S5P_TVOUT_MAX_O_TYPES)
|
| + return -EINVAL;
|
| +
|
| + s5ptv_status.v4l2.output = &s5p_tv_outputs[i];
|
| +
|
| + switch (s5ptv_status.v4l2.output->type) {
|
| +
|
| + case V4L2_OUTPUT_TYPE_COMPOSITE:
|
| + s5ptv_status.tvout_param.out_mode = TVOUT_OUTPUT_COMPOSITE;
|
| + break;
|
| +
|
| + case V4L2_OUTPUT_TYPE_SVIDEO:
|
| + s5ptv_status.tvout_param.out_mode = TVOUT_OUTPUT_SVIDEO;
|
| + break;
|
| +
|
| + case V4L2_OUTPUT_TYPE_YPBPR_INERLACED:
|
| + s5ptv_status.tvout_param.out_mode =
|
| + TVOUT_OUTPUT_COMPONENT_YPBPR_INERLACED;
|
| + break;
|
| +
|
| + case V4L2_OUTPUT_TYPE_YPBPR_PROGRESSIVE:
|
| + s5ptv_status.tvout_param.out_mode =
|
| + TVOUT_OUTPUT_COMPONENT_YPBPR_PROGRESSIVE;
|
| + break;
|
| +
|
| + case V4L2_OUTPUT_TYPE_RGB_PROGRESSIVE:
|
| + s5ptv_status.tvout_param.out_mode = TVOUT_OUTPUT_COMPOSITE;
|
| + break;
|
| +
|
| + case V4L2_OUTPUT_TYPE_HDMI:
|
| + s5ptv_status.tvout_param.out_mode = TVOUT_OUTPUT_HDMI;
|
| + break;
|
| +
|
| + case V4L2_OUTPUT_TYPE_HDMI_RGB:
|
| + s5ptv_status.tvout_param.out_mode = TVOUT_OUTPUT_HDMI_RGB;
|
| + break;
|
| +
|
| + case V4L2_OUTPUT_TYPE_DVI:
|
| + s5ptv_status.tvout_param.out_mode = TVOUT_OUTPUT_DVI;
|
| + break;
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + tv_if_set_disp();
|
| +
|
| + V4L2PRINTK("()--\n");
|
| +
|
| + return 0;
|
| +};
|
| +
|
| +/* Crop ioctls */
|
| +
|
| +/*
|
| + * Video Format Name Pixel aspect ratio Description
|
| + * STD(4:3) Anamorphic(16:9)
|
| + * 640x480 4:3 Used on YouTube
|
| + * 720x576 576i 5:4 64:45 Used on D1/DV PAL
|
| + * 704x576 576p 12:11 16:11 Used on EDTV PAL
|
| + * 720x480 480i 8:9 32:27 Used on DV NTSC
|
| + * 720x486 480i 8:9 32:27 Used on D1 NTSC (ITU-R 601)
|
| + * 704x480 480p 10:11 40:33 Used on EDTV NTSC
|
| + */
|
| +
|
| +static int s5p_tv_v4l2_cropcap(struct file *file, void *fh,
|
| + struct v4l2_cropcap *a)
|
| +{
|
| +
|
| + struct v4l2_cropcap *cropcap = a;
|
| +
|
| + switch (cropcap->type) {
|
| +
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
| + break;
|
| +
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
| + break;
|
| +
|
| + default:
|
| + return -1;
|
| + }
|
| +
|
| + switch (s5ptv_status.tvout_param.disp_mode) {
|
| +
|
| + case TVOUT_NTSC_M:
|
| + case TVOUT_NTSC_443:
|
| + case TVOUT_480P_60_16_9:
|
| + case TVOUT_480P_60_4_3:
|
| + case TVOUT_480P_59:
|
| + cropcap->bounds.top = 0;
|
| + cropcap->bounds.left = 0;
|
| + cropcap->bounds.width = 720;
|
| + cropcap->bounds.height = 480;
|
| +
|
| + cropcap->defrect.top = 0;
|
| + cropcap->defrect.left = 0;
|
| + cropcap->defrect.width = 720;
|
| + cropcap->defrect.height = 480;
|
| + break;
|
| +
|
| + case TVOUT_PAL_M:
|
| + case TVOUT_PAL_BDGHI:
|
| + case TVOUT_PAL_N:
|
| + case TVOUT_PAL_NC:
|
| + case TVOUT_PAL_60:
|
| + case TVOUT_576P_50_16_9:
|
| + case TVOUT_576P_50_4_3:
|
| + cropcap->bounds.top = 0;
|
| + cropcap->bounds.left = 0;
|
| + cropcap->bounds.width = 720;
|
| + cropcap->bounds.height = 576;
|
| +
|
| + cropcap->defrect.top = 0;
|
| + cropcap->defrect.left = 0;
|
| + cropcap->defrect.width = 720;
|
| + cropcap->defrect.height = 576;
|
| + break;
|
| +
|
| + case TVOUT_720P_60:
|
| + case TVOUT_720P_59:
|
| + case TVOUT_720P_50:
|
| + cropcap->bounds.top = 0;
|
| + cropcap->bounds.left = 0;
|
| + cropcap->bounds.width = 1280;
|
| + cropcap->bounds.height = 720;
|
| +
|
| + cropcap->defrect.top = 0;
|
| + cropcap->defrect.left = 0;
|
| + cropcap->defrect.width = 1280;
|
| + cropcap->defrect.height = 720;
|
| + break;
|
| +
|
| + case TVOUT_1080I_60:
|
| + case TVOUT_1080I_59:
|
| + case TVOUT_1080I_50:
|
| + case TVOUT_1080P_60:
|
| + case TVOUT_1080P_59:
|
| + case TVOUT_1080P_50:
|
| + case TVOUT_1080P_30:
|
| + cropcap->bounds.top = 0;
|
| + cropcap->bounds.left = 0;
|
| + cropcap->bounds.width = 1920;
|
| + cropcap->bounds.height = 1080;
|
| +
|
| + cropcap->defrect.top = 0;
|
| + cropcap->defrect.left = 0;
|
| + cropcap->defrect.width = 1920;
|
| + cropcap->defrect.height = 1080;
|
| + break;
|
| +
|
| + default:
|
| + return -1;
|
| +
|
| + }
|
| +
|
| + V4L2PRINTK("[input type 0x%08x] : left: \
|
| + [%d], top [%d], width[%d], height[%d]\n",
|
| + s5ptv_status.tvout_param.disp_mode,
|
| + cropcap->bounds.top ,
|
| + cropcap->bounds.left ,
|
| + cropcap->bounds.width,
|
| + cropcap->bounds.height);
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +static int s5p_tv_v4l2_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
|
| +{
|
| +
|
| + struct v4l2_crop *crop = a;
|
| + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh;
|
| +
|
| + switch (crop->type) {
|
| +
|
| + /* Vlayer */
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
| + crop->c.left = s5ptv_status.vl_basic_param.dest_offset_x;
|
| + crop->c.top = s5ptv_status.vl_basic_param.dest_offset_y;
|
| + crop->c.width = s5ptv_status.vl_basic_param.dest_width;
|
| + crop->c.height = s5ptv_status.vl_basic_param.dest_height;
|
| + break;
|
| +
|
| + /* GRP0/1 */
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
| + crop->c.left = s5ptv_overlay[layer->index].dst_rect.left;
|
| + crop->c.top = s5ptv_overlay[layer->index].dst_rect.top;
|
| + crop->c.width = s5ptv_overlay[layer->index].dst_rect.width;
|
| + crop->c.height = s5ptv_overlay[layer->index].dst_rect.height;
|
| + break;
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +static int s5p_tv_v4l2_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
|
| +{
|
| +
|
| + struct v4l2_crop *crop = a;
|
| + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh;
|
| +
|
| + switch (crop->type) {
|
| +
|
| + /* Vlayer - scaling!! */
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
| +
|
| + s5ptv_status.vl_basic_param.dest_offset_x = crop->c.left;
|
| + s5ptv_status.vl_basic_param.dest_offset_y = crop->c.top;
|
| + s5ptv_status.vl_basic_param.dest_width = crop->c.width;
|
| + s5ptv_status.vl_basic_param.dest_height = crop->c.height;
|
| +
|
| + if (s5ptv_status.vp_layer_enable) {
|
| + struct s5p_img_size img_size;
|
| + struct s5p_img_offset img_offset;
|
| + img_size.img_width = crop->c.width;
|
| + img_size.img_height = crop->c.height;
|
| + img_offset.offset_x = crop->c.left;
|
| + img_offset.offset_y = crop->c.top;
|
| +
|
| + tv_vlayer_set_dest_size((unsigned long)&img_size);
|
| + tv_vlayer_set_dest_position(
|
| + (unsigned long)&img_offset);
|
| + }
|
| + break;
|
| +
|
| + /* GRP0/1 */
|
| + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
|
| + s5ptv_overlay[layer->index].dst_rect.left = crop->c.left;
|
| + s5ptv_overlay[layer->index].dst_rect.top = crop->c.top;
|
| + s5ptv_overlay[layer->index].dst_rect.width
|
| + = crop->c.width;
|
| + s5ptv_overlay[layer->index].dst_rect.height
|
| + = crop->c.height;
|
| + break;
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +/* Stream type-dependent parameter ioctls */
|
| +static int s5p_tv_v4l2_g_parm_v(struct file *file, void *fh,
|
| + struct v4l2_streamparm *a)
|
| +{
|
| +
|
| + struct v4l2_streamparm *param = a;
|
| +
|
| + struct v4l2_window_s5p_tvout vparam;
|
| +
|
| + if (s5ptv_status.vl_basic_param.win_blending) {
|
| + vparam.flags = V4L2_FBUF_FLAG_GLOBAL_ALPHA;
|
| + vparam.capability = V4L2_FBUF_FLAG_GLOBAL_ALPHA;
|
| + }
|
| +
|
| + vparam.win.global_alpha = s5ptv_status.vl_basic_param.alpha;
|
| +
|
| + vparam.priority = s5ptv_status.vl_basic_param.priority;
|
| + vparam.win.w.left = s5ptv_status.vl_basic_param.src_offset_x;
|
| + vparam.win.w.top = s5ptv_status.vl_basic_param.src_offset_y;
|
| + vparam.win.w.width = s5ptv_status.vl_basic_param.src_width;
|
| + vparam.win.w.height = s5ptv_status.vl_basic_param.src_height;
|
| +
|
| + memcpy(param->parm.raw_data, &vparam,
|
| + sizeof(struct v4l2_window_s5p_tvout));
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +static int s5p_tv_v4l2_s_parm_v(struct file *file, void *fh,
|
| + struct v4l2_streamparm *a)
|
| +{
|
| +
|
| + struct v4l2_streamparm *param = a;
|
| +
|
| + struct v4l2_window_s5p_tvout vparam;
|
| +
|
| + memcpy(&vparam, param->parm.raw_data,
|
| + sizeof(struct v4l2_window_s5p_tvout));
|
| +
|
| + s5ptv_status.vl_basic_param.win_blending =
|
| + (vparam.flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) ? 1 : 0;
|
| + s5ptv_status.vl_basic_param.alpha = vparam.win.global_alpha;
|
| + s5ptv_status.vl_basic_param.priority = vparam.priority;
|
| + s5ptv_status.vl_basic_param.src_offset_x = vparam.win.w.left;
|
| + s5ptv_status.vl_basic_param.src_offset_y = vparam.win.w.top;
|
| + s5ptv_status.vl_basic_param.src_width = vparam.win.w.width;
|
| + s5ptv_status.vl_basic_param.src_height = vparam.win.w.height;
|
| +
|
| + V4L2PRINTK("[type 0x%08x] : left: [%d], top [%d], \
|
| + width[%d], height[%d]\n",
|
| + a->type,
|
| + s5ptv_status.vl_basic_param.src_offset_x,
|
| + s5ptv_status.vl_basic_param.src_offset_y,
|
| + s5ptv_status.vl_basic_param.src_width,
|
| + s5ptv_status.vl_basic_param.src_height);
|
| +
|
| + if (s5ptv_status.vp_layer_enable) {
|
| + struct s5p_img_offset img_offset;
|
| + struct s5p_img_size img_size;
|
| +
|
| + img_offset.offset_x = vparam.win.w.left;
|
| + img_offset.offset_y = vparam.win.w.top;
|
| + img_size.img_width = vparam.win.w.width;
|
| + img_size.img_height = vparam.win.w.height;
|
| + tv_vlayer_set_blending(
|
| + s5ptv_status.vl_basic_param.win_blending);
|
| + tv_vlayer_set_alpha(s5ptv_status.vl_basic_param.alpha);
|
| + tv_vlayer_set_priority(vparam.priority);
|
| + tv_vlayer_set_src_position((unsigned long)&img_offset);
|
| + tv_vlayer_set_src_size((unsigned long)&img_size);
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +static int s5p_tv_v4l2_g_parm_vo(struct file *file, void *fh,
|
| + struct v4l2_streamparm *a)
|
| +{
|
| +
|
| + struct v4l2_streamparm *param = a;
|
| +
|
| + struct v4l2_window_s5p_tvout vparam;
|
| + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh;
|
| +
|
| + memset(&vparam, 0, sizeof(struct v4l2_window_s5p_tvout));
|
| +
|
| + V4L2PRINTK("entered\n");
|
| +
|
| + if (s5ptv_overlay[layer->index].win_blending) {
|
| + vparam.flags = V4L2_FBUF_FLAG_GLOBAL_ALPHA;
|
| + vparam.capability = V4L2_FBUF_CAP_GLOBAL_ALPHA;
|
| + }
|
| +
|
| + if (s5ptv_overlay[layer->index].blank_change) {
|
| + vparam.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
|
| + vparam.capability |= V4L2_FBUF_CAP_CHROMAKEY;
|
| + }
|
| +
|
| + if (s5ptv_overlay[layer->index].pixel_blending) {
|
| + vparam.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
|
| + vparam.capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
|
| + }
|
| +
|
| + if (s5ptv_overlay[layer->index].pre_mul) {
|
| + vparam.flags |= V4L2_FBUF_FLAG_PRE_MULTIPLY;
|
| + vparam.capability |= V4L2_FBUF_CAP_PRE_MULTIPLY;
|
| + }
|
| +
|
| + vparam.priority = s5ptv_overlay[layer->index].priority;
|
| +
|
| + vparam.win.chromakey =
|
| + s5ptv_overlay[layer->index].blank_color;
|
| + vparam.win.w.left = s5ptv_overlay[layer->index].dst_rect.left;
|
| + vparam.win.w.top = s5ptv_overlay[layer->index].dst_rect.top;
|
| + vparam.win.w.left = s5ptv_overlay[layer->index].win.w.left;
|
| + vparam.win.w.top = s5ptv_overlay[layer->index].win.w.top;
|
| + vparam.win.w.width = s5ptv_overlay[layer->index].win.w.width;
|
| + vparam.win.w.height = s5ptv_overlay[layer->index].win.w.height;
|
| + vparam.win.global_alpha =
|
| + s5ptv_overlay[layer->index].win.global_alpha;
|
| + vparam.win.w.width =
|
| + s5ptv_overlay[layer->index].fb.fmt.bytesperline;
|
| +
|
| + memcpy(param->parm.raw_data, &vparam,
|
| + sizeof(struct v4l2_window_s5p_tvout));
|
| +
|
| + return 0;
|
| +
|
| +}
|
| +
|
| +
|
| +static int s5p_tv_v4l2_s_parm_vo(struct file *file, void *fh,
|
| + struct v4l2_streamparm *a)
|
| +{
|
| +
|
| + struct v4l2_streamparm *param = a;
|
| +
|
| + struct v4l2_window_s5p_tvout vparam;
|
| +
|
| + struct s5p_tv_vo *layer = (struct s5p_tv_vo *)fh;
|
| + memcpy(&vparam, param->parm.raw_data,
|
| + sizeof(struct v4l2_window_s5p_tvout));
|
| +
|
| + s5ptv_overlay[layer->index].win_blending =
|
| + (vparam.flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) ? 1 : 0;
|
| + s5ptv_overlay[layer->index].blank_change =
|
| + (vparam.flags & V4L2_FBUF_FLAG_CHROMAKEY) ? 1 : 0;
|
| + s5ptv_overlay[layer->index].pixel_blending =
|
| + (vparam.flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) ? 1 : 0;
|
| + s5ptv_overlay[layer->index].pre_mul =
|
| + (vparam.flags & V4L2_FBUF_FLAG_PRE_MULTIPLY) ? 1 : 0;
|
| + s5ptv_overlay[layer->index].priority = vparam.priority;
|
| + s5ptv_overlay[layer->index].blank_color =
|
| + vparam.win.chromakey;
|
| + s5ptv_overlay[layer->index].dst_rect.left = vparam.win.w.left;
|
| + s5ptv_overlay[layer->index].dst_rect.top = vparam.win.w.top;
|
| + s5ptv_overlay[layer->index].win.w.left = vparam.win.w.left;
|
| + s5ptv_overlay[layer->index].win.w.top = vparam.win.w.top;
|
| + s5ptv_overlay[layer->index].win.w.width = vparam.win.w.width;
|
| + s5ptv_overlay[layer->index].win.w.height = vparam.win.w.height;
|
| + s5ptv_overlay[layer->index].win.global_alpha =
|
| + vparam.win.global_alpha;
|
| +
|
| + s5ptv_overlay[layer->index].fb.fmt.bytesperline = vparam.win.w.width;
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +#define VIDIOC_HDCP_ENABLE _IOWR('V', 100, unsigned int)
|
| +#define VIDIOC_HDCP_STATUS _IOR('V', 101, unsigned int)
|
| +#define VIDIOC_HDCP_PROT_STATUS _IOR('V', 102, unsigned int)
|
| +
|
| +long s5p_tv_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
| +{
|
| + switch (cmd) {
|
| +
|
| + case VIDIOC_HDCP_ENABLE:
|
| + s5ptv_status.hdcp_en = (unsigned int) arg;
|
| + V4L2PRINTK("HDCP status is %s\n",
|
| + s5ptv_status.hdcp_en ? "enabled" : "disabled");
|
| + return 0;
|
| +
|
| + case VIDIOC_HDCP_STATUS: {
|
| +
|
| + unsigned int *status = (unsigned int *)&arg;
|
| +
|
| + *status = 1;
|
| +
|
| + V4L2PRINTK("HPD status is %s\n",
|
| + s5ptv_status.hpd_status ? "plugged" : "unplugged");
|
| + return 0;
|
| + }
|
| +
|
| + case VIDIOC_HDCP_PROT_STATUS: {
|
| +
|
| + unsigned int *prot = (unsigned int *)&arg;
|
| +
|
| + *prot = 1;
|
| +
|
| + V4L2PRINTK("hdcp prot status is %d\n",
|
| + hdcp_protocol_status);
|
| + return 0;
|
| + }
|
| +
|
| + case VIDIOC_ENUMSTD: {
|
| +
|
| + struct v4l2_standard *p = (struct v4l2_standard *)arg;
|
| +
|
| + if (p->index >= S5P_TVOUT_MAX_STANDARDS) {
|
| + V4L2PRINTK("exceeded S5P_TVOUT_MAX_STANDARDS\n");
|
| + return -EINVAL;
|
| + }
|
| +
|
| + memcpy(p, &s5p_tv_standards[p->index],
|
| + sizeof(struct v4l2_standard));
|
| + return 0;
|
| + }
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return video_ioctl2(file, cmd, arg);
|
| +}
|
| +
|
| +long s5p_tv_vid_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
| +{
|
| + struct video_device *vfd = video_devdata(file);
|
| + const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
|
| +
|
| + switch (cmd) {
|
| +
|
| + case VIDIOC_S_FMT: {
|
| + struct v4l2_format *f = (struct v4l2_format *)arg;
|
| + void *fh = file->private_data;
|
| + long ret = -EINVAL;
|
| +
|
| + if (ops->vidioc_s_fmt_vid_out)
|
| + ret = ops->vidioc_s_fmt_vid_out(file, fh, f);
|
| + return ret;
|
| + }
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return video_ioctl2(file, cmd, arg);
|
| +}
|
| +
|
| +
|
| +long s5p_tv_v_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
| +{
|
| + struct video_device *vfd = video_devdata(file);
|
| + const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
|
| +
|
| + switch (cmd) {
|
| +
|
| + case VIDIOC_S_FMT: {
|
| + struct v4l2_format *f = (struct v4l2_format *)arg;
|
| + void *fh = file->private_data;
|
| + long ret = -EINVAL;
|
| +
|
| + if (ops->vidioc_s_fmt_vid_out)
|
| + ret = ops->vidioc_s_fmt_vid_out(file, fh, f);
|
| + return ret;
|
| + }
|
| +
|
| + case VIDIOC_HDCP_ENABLE:
|
| + s5ptv_status.hdcp_en = (unsigned int) arg;
|
| + V4L2PRINTK("HDCP status is %s\n",
|
| + s5ptv_status.hdcp_en ? "enabled" : "disabled");
|
| + return 0;
|
| +
|
| + case VIDIOC_HDCP_STATUS: {
|
| +
|
| + unsigned int *status = (unsigned int *)&arg;
|
| +
|
| + *status = 1;
|
| +
|
| + V4L2PRINTK("HPD status is %s\n",
|
| + s5ptv_status.hpd_status ? "plugged" : "unplugged");
|
| + return 0;
|
| + }
|
| +
|
| + case VIDIOC_HDCP_PROT_STATUS: {
|
| +
|
| + unsigned int *prot = (unsigned int *)&arg;
|
| +
|
| + *prot = 1;
|
| +
|
| + V4L2PRINTK("hdcp prot status is %d\n",
|
| + hdcp_protocol_status);
|
| + return 0;
|
| + }
|
| +
|
| + case VIDIOC_ENUMSTD: {
|
| +
|
| + struct v4l2_standard *p = (struct v4l2_standard *)arg;
|
| +
|
| + if (p->index >= S5P_TVOUT_MAX_STANDARDS) {
|
| + V4L2PRINTK("exceeded S5P_TVOUT_MAX_STANDARDS\n");
|
| + return -EINVAL;
|
| + }
|
| +
|
| + memcpy(p, &s5p_tv_standards[p->index],
|
| + sizeof(struct v4l2_standard));
|
| +
|
| + return 0;
|
| + }
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return video_ioctl2(file, cmd, arg);
|
| +}
|
| +
|
| +long s5p_tv_vo_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
| +{
|
| + void *fh = file->private_data;
|
| +
|
| + switch (cmd) {
|
| +
|
| + case VIDIOC_ENUM_FMT: {
|
| +
|
| + struct v4l2_fmtdesc *f = (struct v4l2_fmtdesc *)arg;
|
| + enum v4l2_buf_type type;
|
| + unsigned int index;
|
| +
|
| + index = f->index;
|
| + type = f->type;
|
| +
|
| + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) {
|
| + memset(f, 0, sizeof(*f));
|
| + f->index = index;
|
| + f->type = type;
|
| +
|
| + return s5p_tv_v4l2_enum_fmt_vid_out_overlay(
|
| + file, fh, f);
|
| + }
|
| +
|
| + break;
|
| + }
|
| +
|
| + case VIDIOC_G_FMT: {
|
| +
|
| + struct v4l2_format *f = (struct v4l2_format *)arg;
|
| +
|
| + return s5p_tv_v4l2_g_fmt_vid_out_overlay(file, fh, f);
|
| + }
|
| +
|
| + break;
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + /*
|
| + * in 2.6.28 version Mauro Carvalho Chehab added for removing inode
|
| + * but 2.6.29 is not applied. what is it?
|
| + */
|
| + return video_ioctl2(file, cmd, arg);
|
| +}
|
| +
|
| +const struct v4l2_ioctl_ops s5p_tv_v4l2_ops = {
|
| + .vidioc_querycap = s5p_tv_v4l2_querycap,
|
| + .vidioc_g_std = s5p_tv_v4l2_g_std,
|
| + .vidioc_s_std = s5p_tv_v4l2_s_std,
|
| + .vidioc_enum_output = s5p_tv_v4l2_enum_output,
|
| + .vidioc_g_output = s5p_tv_v4l2_g_output,
|
| + .vidioc_s_output = s5p_tv_v4l2_s_output,
|
| +};
|
| +
|
| +const struct v4l2_ioctl_ops s5p_tv_v4l2_vid_ops = {
|
| + .vidioc_querycap = s5p_tv_v4l2_querycap,
|
| + .vidioc_enum_fmt_vid_out = s5p_tv_v4l2_enum_fmt_vid_out,
|
| + .vidioc_g_fmt_vid_out = s5p_tv_v4l2_g_fmt_vid_out,
|
| + .vidioc_s_fmt_vid_out = s5p_tv_v4l2_s_fmt_vid_out,
|
| + .vidioc_streamon = s5p_tv_v4l2_streamon,
|
| + .vidioc_streamoff = s5p_tv_v4l2_streamoff,
|
| + .vidioc_cropcap = s5p_tv_v4l2_cropcap,
|
| + .vidioc_g_crop = s5p_tv_v4l2_g_crop,
|
| + .vidioc_s_crop = s5p_tv_v4l2_s_crop,
|
| + .vidioc_g_parm = s5p_tv_v4l2_g_parm_v,
|
| + .vidioc_s_parm = s5p_tv_v4l2_s_parm_v,
|
| +};
|
| +
|
| +const struct v4l2_ioctl_ops s5p_tv_v4l2_v_ops = {
|
| + .vidioc_querycap = s5p_tv_v4l2_querycap,
|
| + .vidioc_enum_fmt_vid_out = s5p_tv_v4l2_enum_fmt_vid_out,
|
| + .vidioc_g_fmt_vid_out = s5p_tv_v4l2_g_fmt_vid_out,
|
| + .vidioc_s_fmt_vid_out = s5p_tv_v4l2_s_fmt_vid_out,
|
| + .vidioc_streamon = s5p_tv_v4l2_streamon,
|
| + .vidioc_streamoff = s5p_tv_v4l2_streamoff,
|
| + .vidioc_g_std = s5p_tv_v4l2_g_std,
|
| + .vidioc_s_std = s5p_tv_v4l2_s_std,
|
| + .vidioc_enum_output = s5p_tv_v4l2_enum_output,
|
| + .vidioc_g_output = s5p_tv_v4l2_g_output,
|
| + .vidioc_s_output = s5p_tv_v4l2_s_output,
|
| + .vidioc_cropcap = s5p_tv_v4l2_cropcap,
|
| + .vidioc_g_crop = s5p_tv_v4l2_g_crop,
|
| + .vidioc_s_crop = s5p_tv_v4l2_s_crop,
|
| + .vidioc_g_parm = s5p_tv_v4l2_g_parm_v,
|
| + .vidioc_s_parm = s5p_tv_v4l2_s_parm_v,
|
| +};
|
| +
|
| +const struct v4l2_ioctl_ops s5p_tv_v4l2_vo_ops = {
|
| + .vidioc_querycap = s5p_tv_v4l2_querycap,
|
| + .vidioc_g_fmt_vid_out_overlay = s5p_tv_v4l2_g_fmt_vid_out_overlay,
|
| + .vidioc_s_fmt_vid_out_overlay = s5p_tv_v4l2_s_fmt_vid_out_overlay,
|
| + .vidioc_overlay = s5p_tv_v4l2_overlay,
|
| + .vidioc_g_fbuf = s5p_tv_v4l2_g_fbuf,
|
| + .vidioc_s_fbuf = s5p_tv_v4l2_s_fbuf,
|
| + .vidioc_streamon = s5p_tv_v4l2_streamon,
|
| + .vidioc_streamoff = s5p_tv_v4l2_streamoff,
|
| + .vidioc_cropcap = s5p_tv_v4l2_cropcap,
|
| + .vidioc_g_crop = s5p_tv_v4l2_g_crop,
|
| + .vidioc_s_crop = s5p_tv_v4l2_s_crop,
|
| + .vidioc_g_parm = s5p_tv_v4l2_g_parm_vo,
|
| + .vidioc_s_parm = s5p_tv_v4l2_s_parm_vo,
|
| +};
|
| +
|
|
|