msm: vidc: wfd: Add WFD support for msm8974

Adds three new subdevices:
- Encoder subdevice to interface with new venus driver
    o Renamed enc-subdev.c to enc-mfc-subdev.c which only
      compiles for targets using the Samsung MFC core.
- MDP subdevice to interface with new MDSS driver
    o Renamed mdp-subdev.c to mdp-4-subdev.c used for targets
      using MDP4.
- MDP subdevice for debugging purposes
- Introduce a Kconfig file to properly choose between subdevices
  according to target

Change-Id: I125b39cfdeb1fbb4adf7c15d0c4452146764f985
Signed-off-by: Deva Ramasubramanian <dramasub@codeaurora.org>
Signed-off-by: Amara Venkata Mastan Manoj Kumar <manojavm@codeaurora.org>
This commit is contained in:
Deva Ramasubramanian 2012-07-31 11:11:15 -07:00 committed by Stephen Boyd
parent e64f038561
commit e0f91c62fa
14 changed files with 1627 additions and 46 deletions

View file

@ -171,6 +171,11 @@ CONFIG_VIDEOBUF2_MSM_MEM=y
# CONFIG_RADIO_ADAPTERS is not set
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_MSM_CAMERA_V4L2=y
<<<<<<< HEAD
=======
CONFIG_MSM_WFD=y
CONFIG_OV2720=y
>>>>>>> 1efb995... msm: vidc: wfd: Add WFD support for msm8974
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
CONFIG_MSM_CAM_IRQ_ROUTER=n

View file

@ -1262,3 +1262,4 @@ config VIDEO_MX2_EMMAPRP
endif # V4L_MEM2MEM_DRIVERS
source "drivers/media/video/msm_vidc/Kconfig"
source "drivers/media/video/msm_wfd/Kconfig"

View file

@ -215,7 +215,7 @@ obj-y += davinci/
obj-$(CONFIG_MSM_CAMERA) += msm/
obj-$(CONFIG_ARCH_OMAP) += omap/
obj-$(CONFIG_MSM_VIDC_V4L2) += msm_vidc/
obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += msm_wfd/
obj-$(CONFIG_MSM_WFD) += msm_wfd/
ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb/frontends

View file

@ -0,0 +1,6 @@
menuconfig MSM_WFD
bool "Qualcomm MSM Wifi Display Driver"
depends on (MSM_VIDC_1080P || MSM_VIDC_V4L2)
---help---
Enables the Wifi Display driver.

View file

@ -1,5 +1,14 @@
obj-y += mdp-subdev.o
obj-y += enc-subdev.o
obj-y += vsg-subdev.o
obj-y += wfd-ioctl.o
obj-y += wfd-util.o
ifeq ($(CONFIG_MSM_WFD),y)
obj-y += wfd-ioctl.o
obj-y += wfd-util.o
obj-y += vsg-subdev.o
ifeq ($(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL),y)
obj-y += mdp-4-subdev.o
else ifeq ($(CONFIG_FB_MSM_MDSS_WRITEBACK),y)
obj-y += mdp-5-subdev.o
else
obj-y += mdp-dummy-subdev.o
endif
obj-$(CONFIG_MSM_VIDC_1080P) += enc-mfc-subdev.o
obj-$(CONFIG_MSM_VIDC_V4L2) += enc-venus-subdev.o
endif

View file

@ -227,7 +227,7 @@ static void venc_cb(u32 event, u32 status, void *info, u32 size, void *handle,
BUFFER_TYPE_OUTPUT, pmem_fd,
kvaddr, buffer_index, &ion_handle);
else
WFD_MSG_ERR("Got an output buffer that we "
WFD_MSG_ERR("Got an output buffer that we " \
"couldn't recognize!\n");
if (msm_ion_do_cache_op(client_ctx->user_ion_client,
@ -547,8 +547,8 @@ static long venc_set_codec_level(struct video_client_ctx *client_ctx,
if (vcd_property_level.level < VCD_LEVEL_MPEG4_0
|| vcd_property_level.level > VCD_LEVEL_MPEG4_X) {
WFD_MSG_ERR("Level (%d) out of range"
"for codec (%d)\n", level, codec);
WFD_MSG_ERR("Level (%d) out of range for codec (%d)\n",
level, codec);
rc = -EINVAL;
goto err;
@ -558,8 +558,8 @@ static long venc_set_codec_level(struct video_client_ctx *client_ctx,
if (vcd_property_level.level < VCD_LEVEL_H264_1
|| vcd_property_level.level > VCD_LEVEL_H264_5p1) {
WFD_MSG_ERR("Level (%d) out of range"
"for codec (%d)\n", level, codec);
WFD_MSG_ERR("Level (%d) out of range for codec (%d)\n",
level, codec);
rc = -EINVAL;
goto err;
@ -678,9 +678,9 @@ static long venc_set_codec_profile(struct video_client_ctx *client_ctx,
vcd_property_profile.profile = VCD_PROFILE_MPEG4_ASP;
break;
default:
WFD_MSG_ERR("Profile %d not supported,"
"defaulting to simple (%d)",
profile, VCD_PROFILE_MPEG4_SP);
WFD_MSG_ERR("Profile %d not supported, defaulting " \
"to simple (%d)", profile,
VCD_PROFILE_MPEG4_SP);
vcd_property_profile.profile = VCD_PROFILE_MPEG4_SP;
break;
}
@ -697,17 +697,16 @@ static long venc_set_codec_profile(struct video_client_ctx *client_ctx,
vcd_property_profile.profile = VCD_PROFILE_H264_HIGH;
break;
default:
WFD_MSG_ERR("Profile %d not supported,"
"defaulting to baseline (%d)",
profile, VCD_PROFILE_H264_BASELINE);
WFD_MSG_ERR("Profile %d not supported, defaulting " \
"to baseline (%d)", profile,
VCD_PROFILE_H264_BASELINE);
vcd_property_profile.profile =
VCD_PROFILE_H264_BASELINE;
break;
}
} else {
WFD_MSG_ERR("Codec (%d) not supported,"
"not setting profile (%d)",
codec, profile);
WFD_MSG_ERR("Codec (%d) not supported, not "\
"setting profile (%d)", codec, profile);
rc = -ENOTSUPP;
goto err_set_profile;
}

View file

@ -14,7 +14,8 @@
#ifndef _WFD_ENC_SUBDEV_
#define _WFD_ENC_SUBDEV_
#include <linux/ion.h>
#include <linux/list.h>
#include <linux/msm_ion.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-core.h>
#define VENC_MAGIC_IOCTL 'V'
@ -29,6 +30,7 @@ struct mem_region {
u32 cookie;
struct ion_handle *ion_handle;
};
struct bufreq {
u32 count;
u32 height;
@ -44,13 +46,27 @@ struct venc_buf_info {
struct venc_msg_ops {
void *cookie;
void *cbdata;
int secure;
bool secure;
void (*op_buffer_done)(void *cookie, u32 status,
struct vb2_buffer *buf);
void (*ip_buffer_done)(void *cookie, u32 status,
struct mem_region *mregion);
};
static inline bool mem_region_equals(struct mem_region *a,
struct mem_region *b)
{
if (a == b)
return true;
else if (a->fd || b->fd)
return (a->fd == b->fd) &&
(a->offset == b->offset);
else if (a->kvaddr || b->kvaddr)
return a->kvaddr == b->kvaddr;
else
return false;
}
#define OPEN _IOR('V', 1, void *)
#define CLOSE _IO('V', 2)
#define ENCODE_START _IO('V', 3)

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,8 @@ struct mdp_instance {
struct fb_info *mdp;
u32 height;
u32 width;
bool secure;
bool uses_iommu_split_domain;
};
int mdp_init(struct v4l2_subdev *sd, u32 val)
@ -29,34 +31,42 @@ int mdp_open(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
GFP_KERNEL);
void **cookie = (void **)arg;
struct mdp_msg_ops *mops = arg;
int rc = 0;
struct fb_info *fbi = NULL;
if (!inst) {
WFD_MSG_ERR("Out of memory\n");
return -ENOMEM;
rc = -ENOMEM;
goto mdp_open_fail;
} else if (!mops) {
WFD_MSG_ERR("Invalid arguments\n");
rc = -EINVAL;
goto mdp_open_fail;
}
fbi = msm_fb_get_writeback_fb();
if (!fbi) {
WFD_MSG_ERR("Failed to acquire mdp instance\n");
rc = -ENODEV;
goto exit;
goto mdp_open_fail;
}
/*Tell HDMI daemon to open fb2*/
rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ADD);
if (rc) {
WFD_MSG_ERR("Failed add to kobj");
goto exit;
goto mdp_open_fail;
}
msm_fb_writeback_init(fbi);
inst->mdp = fbi;
*cookie = inst;
inst->secure = mops->secure;
inst->uses_iommu_split_domain = mops->iommu_split_domain;
mops->cookie = inst;
return rc;
exit:
mdp_open_fail:
kfree(inst);
return rc;
}
@ -134,8 +144,8 @@ int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
fbdata.flags = 0;
fbdata.priv = (uint32_t)binfo->cookie;
WFD_MSG_INFO("queue buffer to mdp with offset = %u,"
"fd = %u, priv = %p, iova = %p\n",
WFD_MSG_INFO("queue buffer to mdp with offset = %u, fd = %u, "\
"priv = %p, iova = %p\n",
fbdata.offset, fbdata.memory_id,
(void *)fbdata.priv, (void *)fbdata.iova);
rc = msm_fb_writeback_queue_buffer(inst->mdp, &fbdata);
@ -179,6 +189,7 @@ int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
inst->width = prop->width;
return 0;
}
long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
int rc = 0;

View file

@ -0,0 +1,229 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/msm_mdp.h>
#include <mach/iommu_domains.h>
#include <media/videobuf2-core.h>
#include "enc-subdev.h"
#include "mdp-subdev.h"
#include "wfd-util.h"
struct mdp_instance {
struct fb_info *mdp;
u32 height;
u32 width;
bool secure;
};
int mdp_init(struct v4l2_subdev *sd, u32 val)
{
return 0;
}
int mdp_open(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
GFP_KERNEL);
struct mdp_msg_ops *mops = arg;
int rc = 0;
struct fb_info *fbi = NULL;
if (!inst) {
WFD_MSG_ERR("Out of memory\n");
rc = -ENOMEM;
goto mdp_open_fail;
} else if (!mops) {
WFD_MSG_ERR("Invalid arguments\n");
rc = -EINVAL;
goto mdp_open_fail;
}
fbi = msm_fb_get_writeback_fb();
if (!fbi) {
WFD_MSG_ERR("Failed to acquire mdp instance\n");
rc = -ENODEV;
goto mdp_open_fail;
}
/*Tell HDMI daemon to open fb2*/
rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ADD);
if (rc)
WFD_MSG_ERR("Failed add to kobj");
msm_fb_writeback_init(fbi);
inst->mdp = fbi;
inst->secure = mops->secure;
mops->cookie = inst;
return rc;
mdp_open_fail:
kfree(inst);
return rc;
}
int mdp_start(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = arg;
int rc = 0;
struct fb_info *fbi = NULL;
if (inst) {
rc = msm_fb_writeback_start(inst->mdp);
if (rc) {
WFD_MSG_ERR("Failed to start MDP mode\n");
goto exit;
}
fbi = msm_fb_get_writeback_fb();
if (!fbi) {
WFD_MSG_ERR("Failed to acquire mdp instance\n");
rc = -ENODEV;
goto exit;
}
rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ONLINE);
if (rc)
WFD_MSG_ERR("Failed to send ONLINE event\n");
}
exit:
return rc;
}
int mdp_stop(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = arg;
int rc = 0;
struct fb_info *fbi = NULL;
if (inst) {
rc = msm_fb_writeback_stop(inst->mdp);
if (rc) {
WFD_MSG_ERR("Failed to stop writeback mode\n");
return rc;
}
fbi = (struct fb_info *)inst->mdp;
rc = kobject_uevent(&fbi->dev->kobj, KOBJ_OFFLINE);
if (rc) {
WFD_MSG_ERR("Failed to send offline event\n");
return -EIO;
}
}
return 0;
}
int mdp_close(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = arg;
struct fb_info *fbi = NULL;
if (inst) {
fbi = (struct fb_info *)inst->mdp;
msm_fb_writeback_terminate(fbi);
kfree(inst);
}
return 0;
}
int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
{
int rc = 0;
struct mdp_buf_info *binfo = arg;
struct msmfb_data fbdata;
struct mdp_instance *inst;
if (!binfo || !binfo->inst || !binfo->cookie) {
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
}
inst = binfo->inst;
fbdata.offset = binfo->offset;
fbdata.memory_id = binfo->fd;
fbdata.iova = binfo->paddr;
fbdata.id = 0;
fbdata.flags = 0;
fbdata.priv = (uint32_t)binfo->cookie;
WFD_MSG_DBG("queue buffer to mdp with offset = %u, fd = %u, "\
"priv = %p, iova = %p\n",
fbdata.offset, fbdata.memory_id,
(void *)fbdata.priv, (void *)fbdata.iova);
rc = msm_fb_writeback_queue_buffer(inst->mdp, &fbdata);
if (rc)
WFD_MSG_ERR("Failed to queue buffer\n");
return rc;
}
int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
{
int rc = 0;
struct mdp_buf_info *obuf = arg;
struct msmfb_data fbdata;
struct mdp_instance *inst;
if (!arg) {
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
}
inst = obuf->inst;
fbdata.flags = MSMFB_WRITEBACK_DEQUEUE_BLOCKING;
rc = msm_fb_writeback_dequeue_buffer(inst->mdp, &fbdata);
if (rc) {
WFD_MSG_ERR("Failed to dequeue buffer\n");
return rc;
}
WFD_MSG_DBG("dequeue buf from mdp with priv = %u\n",
fbdata.priv);
obuf->cookie = (void *)fbdata.priv;
return rc;
}
int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
{
struct mdp_prop *prop = (struct mdp_prop *)arg;
struct mdp_instance *inst = prop->inst;
if (!prop || !inst) {
WFD_MSG_ERR("Invalid arguments\n");
return -EINVAL;
}
inst->height = prop->height;
inst->width = prop->width;
return 0;
}
long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
int rc = 0;
if (!sd) {
WFD_MSG_ERR("Invalid arguments\n");
return -EINVAL;
}
switch (cmd) {
case MDP_Q_BUFFER:
rc = mdp_q_buffer(sd, arg);
break;
case MDP_DQ_BUFFER:
rc = mdp_dq_buffer(sd, arg);
break;
case MDP_OPEN:
rc = mdp_open(sd, arg);
break;
case MDP_START:
rc = mdp_start(sd, arg);
break;
case MDP_STOP:
rc = mdp_stop(sd, arg);
break;
case MDP_SET_PROP:
rc = mdp_set_prop(sd, arg);
break;
case MDP_CLOSE:
rc = mdp_close(sd, arg);
break;
default:
WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
rc = -EINVAL;
break;
}
return rc;
}

View file

@ -0,0 +1,162 @@
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/list.h>
#include <linux/msm_mdp.h>
#include <media/videobuf2-core.h>
#include "mdp-subdev.h"
#include "wfd-util.h"
struct mdp_buf_queue {
struct mdp_buf_info mdp_buf_info;
struct list_head node;
};
struct mdp_instance {
struct mdp_buf_queue mdp_bufs;
struct mutex mutex;
};
int mdp_init(struct v4l2_subdev *sd, u32 val)
{
return 0;
}
int mdp_open(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
GFP_KERNEL);
void **cookie = (void **)arg;
int rc = 0;
if (!inst) {
WFD_MSG_ERR("Out of memory\n");
return -ENOMEM;
}
INIT_LIST_HEAD(&inst->mdp_bufs.node);
mutex_init(&inst->mutex);
*cookie = inst;
return rc;
}
int mdp_start(struct v4l2_subdev *sd, void *arg)
{
return 0;
}
int mdp_stop(struct v4l2_subdev *sd, void *arg)
{
return 0;
}
int mdp_close(struct v4l2_subdev *sd, void *arg)
{
return 0;
}
int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
{
static int foo;
int rc = 0;
struct mdp_buf_info *binfo = arg;
struct mdp_instance *inst = NULL;
if (!binfo || !binfo->inst || !binfo->cookie) {
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
}
inst = binfo->inst;
if (binfo->kvaddr) {
struct mdp_buf_queue *new_entry = kzalloc(sizeof(*new_entry),
GFP_KERNEL);
memset((void *)binfo->kvaddr, foo++, 1024);
new_entry->mdp_buf_info = *binfo;
mutex_lock(&inst->mutex);
list_add_tail(&new_entry->node, &inst->mdp_bufs.node);
mutex_unlock(&inst->mutex);
WFD_MSG_DBG("Queue %p with cookie %p\n",
(void *)binfo->paddr, (void *)binfo->cookie);
} else {
rc = -EINVAL;
}
return rc;
}
int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
{
struct mdp_buf_info *binfo = arg;
struct mdp_buf_queue *head = NULL;
struct mdp_instance *inst = NULL;
inst = binfo->inst;
while (head == NULL) {
mutex_lock(&inst->mutex);
if (!list_empty(&inst->mdp_bufs.node))
head = list_first_entry(&inst->mdp_bufs.node,
struct mdp_buf_queue, node);
mutex_unlock(&inst->mutex);
}
if (head == NULL)
return -ENOBUFS;
mutex_lock(&inst->mutex);
list_del(&head->node);
mutex_unlock(&inst->mutex);
*binfo = head->mdp_buf_info;
WFD_MSG_DBG("Dequeue %p with cookie %p\n",
(void *)binfo->paddr, (void *)binfo->cookie);
return 0;
}
int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
{
return 0;
}
long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
int rc = 0;
if (!sd) {
WFD_MSG_ERR("Invalid arguments\n");
return -EINVAL;
}
switch (cmd) {
case MDP_Q_BUFFER:
rc = mdp_q_buffer(sd, arg);
break;
case MDP_DQ_BUFFER:
rc = mdp_dq_buffer(sd, arg);
break;
case MDP_OPEN:
rc = mdp_open(sd, arg);
break;
case MDP_START:
rc = mdp_start(sd, arg);
break;
case MDP_STOP:
rc = mdp_stop(sd, arg);
break;
case MDP_SET_PROP:
rc = mdp_set_prop(sd, arg);
break;
case MDP_CLOSE:
rc = mdp_close(sd, arg);
break;
default:
WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
rc = -EINVAL;
break;
}
return rc;
}

View file

@ -34,6 +34,12 @@ struct mdp_prop {
u32 width;
};
struct mdp_msg_ops {
void *cookie;
bool secure;
bool iommu_split_domain;
};
static inline bool mdp_buf_info_equals(struct mdp_buf_info *a,
struct mdp_buf_info *b)
{

View file

@ -10,7 +10,6 @@
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/list.h>
@ -40,8 +39,8 @@
#define WFD_NUM_DEVICES 2
#define WFD_DEVICE_NUMBER_BASE 38
#define WFD_DEVICE_SECURE (WFD_DEVICE_NUMBER_BASE + 1)
#define DEFAULT_WFD_WIDTH 640
#define DEFAULT_WFD_HEIGHT 480
#define DEFAULT_WFD_WIDTH 1280
#define DEFAULT_WFD_HEIGHT 720
#define VENC_INPUT_BUFFERS 4
struct wfd_device {
@ -882,7 +881,7 @@ static int wfd_register_out_buf(struct wfd_inst *inst,
list_add_tail(&minfo_entry->list, &inst->minfo_list);
spin_unlock_irqrestore(&inst->inst_lock, flags);
} else
WFD_MSG_INFO("Buffer already registered\n");
WFD_MSG_DBG("Buffer already registered\n");
return 0;
}
@ -968,7 +967,7 @@ static int wfdioc_dqbuf(struct file *filp, void *fh,
struct wfd_inst *inst = filp->private_data;
int rc;
WFD_MSG_INFO("Waiting to dequeue buffer\n");
WFD_MSG_DBG("Waiting to dequeue buffer\n");
rc = vb2_dqbuf(&inst->vid_bufq, b, 0);
if (rc)
@ -1304,6 +1303,7 @@ static int wfd_open(struct file *filp)
struct wfd_inst *inst = NULL;
struct wfd_device *wfd_dev = NULL;
struct venc_msg_ops enc_mops;
struct mdp_msg_ops mdp_mops;
struct vsg_msg_ops vsg_mops;
WFD_MSG_DBG("wfd_open: E\n");
@ -1337,12 +1337,15 @@ static int wfd_open(struct file *filp)
wfd_stats_init(&inst->stats, MINOR(filp->f_dentry->d_inode->i_rdev));
mdp_mops.secure = wfd_dev->secure_device;
mdp_mops.iommu_split_domain = wfd_dev->mdp_iommu_split_domain;
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_OPEN,
(void *)&inst->mdp_inst);
(void *)&mdp_mops);
if (rc) {
WFD_MSG_ERR("Failed to open mdp subdevice: %d\n", rc);
goto err_mdp_open;
}
inst->mdp_inst = mdp_mops.cookie;
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, load_fw);
if (rc) {

View file

@ -21,16 +21,11 @@
/*#define DEBUG_WFD*/
#define WFD_TAG "wfd: "
#ifdef DEBUG_WFD
#define WFD_MSG_INFO(fmt...) pr_info(WFD_TAG fmt)
#define WFD_MSG_WARN(fmt...) pr_warning(WFD_TAG fmt)
#else
#define WFD_MSG_INFO(fmt...)
#define WFD_MSG_WARN(fmt...)
#endif
#define WFD_MSG_ERR(fmt...) pr_err(KERN_ERR WFD_TAG fmt)
#define WFD_MSG_CRIT(fmt...) pr_crit(KERN_CRIT WFD_TAG fmt)
#define WFD_MSG_DBG(fmt...) pr_debug(WFD_TAG fmt)
#define WFD_MSG_INFO(fmt...) pr_info(WFD_TAG fmt)
#define WFD_MSG_WARN(fmt...) pr_warning(WFD_TAG fmt)
#define WFD_MSG_ERR(fmt...) pr_err(KERN_ERR WFD_TAG fmt)
#define WFD_MSG_CRIT(fmt...) pr_crit(KERN_CRIT WFD_TAG fmt)
#define WFD_MSG_DBG(fmt...) pr_debug(WFD_TAG fmt)
struct wfd_stats_encode_sample {