Commit 593f4b19 authored by Ville Syrjälä's avatar Ville Syrjälä

video/hdmi: Allow "empty" HDMI infoframes

HDMI 2.0 Appendix F suggest that we should keep sending the infoframe
when switching from 3D to 2D mode, even if the infoframe isn't strictly
necessary (ie. not needed to transmit the VIC or stereo information).
This is a workaround against some sinks that fail to realize that they
should switch from 3D to 2D mode when the source stop transmitting
the infoframe.

v2: Handle unpack() as well
    Pull the length calculation into a helper

Cc: Shashank Sharma <shashank.sharma@intel.com>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com> #v1
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171113170427.4150-2-ville.syrjala@linux.intel.comReviewed-by: default avatarShashank Sharma <shashank.sharma@intel.com>
parent 03e4e0a9
...@@ -321,6 +321,17 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame) ...@@ -321,6 +321,17 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
} }
EXPORT_SYMBOL(hdmi_vendor_infoframe_init); EXPORT_SYMBOL(hdmi_vendor_infoframe_init);
static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame)
{
/* for side by side (half) we also need to provide 3D_Ext_Data */
if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
return 6;
else if (frame->vic != 0 || frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
return 5;
else
return 4;
}
/** /**
* hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
* @frame: HDMI infoframe * @frame: HDMI infoframe
...@@ -341,19 +352,11 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, ...@@ -341,19 +352,11 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
u8 *ptr = buffer; u8 *ptr = buffer;
size_t length; size_t length;
/* empty info frame */
if (frame->vic == 0 && frame->s3d_struct == HDMI_3D_STRUCTURE_INVALID)
return -EINVAL;
/* only one of those can be supplied */ /* only one of those can be supplied */
if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
return -EINVAL; return -EINVAL;
/* for side by side (half) we also need to provide 3D_Ext_Data */ frame->length = hdmi_vendor_infoframe_length(frame);
if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
frame->length = 6;
else
frame->length = 5;
length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
...@@ -372,14 +375,16 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, ...@@ -372,14 +375,16 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
ptr[5] = 0x0c; ptr[5] = 0x0c;
ptr[6] = 0x00; ptr[6] = 0x00;
if (frame->vic) { if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
ptr[7] = 0x1 << 5; /* video format */
ptr[8] = frame->vic;
} else {
ptr[7] = 0x2 << 5; /* video format */ ptr[7] = 0x2 << 5; /* video format */
ptr[8] = (frame->s3d_struct & 0xf) << 4; ptr[8] = (frame->s3d_struct & 0xf) << 4;
if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
ptr[9] = (frame->s3d_ext_data & 0xf) << 4; ptr[9] = (frame->s3d_ext_data & 0xf) << 4;
} else if (frame->vic) {
ptr[7] = 0x1 << 5; /* video format */
ptr[8] = frame->vic;
} else {
ptr[7] = 0x0 << 5; /* video format */
} }
hdmi_infoframe_set_checksum(buffer, length); hdmi_infoframe_set_checksum(buffer, length);
...@@ -1165,7 +1170,7 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame, ...@@ -1165,7 +1170,7 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR || if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
ptr[1] != 1 || ptr[1] != 1 ||
(ptr[2] != 5 && ptr[2] != 6)) (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
return -EINVAL; return -EINVAL;
length = ptr[2]; length = ptr[2];
...@@ -1193,16 +1198,22 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame, ...@@ -1193,16 +1198,22 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
hvf->length = length; hvf->length = length;
if (hdmi_video_format == 0x1) { if (hdmi_video_format == 0x2) {
hvf->vic = ptr[4]; if (length != 5 && length != 6)
} else if (hdmi_video_format == 0x2) { return -EINVAL;
hvf->s3d_struct = ptr[4] >> 4; hvf->s3d_struct = ptr[4] >> 4;
if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) { if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
if (length == 6) if (length != 6)
hvf->s3d_ext_data = ptr[5] >> 4;
else
return -EINVAL; return -EINVAL;
hvf->s3d_ext_data = ptr[5] >> 4;
} }
} else if (hdmi_video_format == 0x1) {
if (length != 5)
return -EINVAL;
hvf->vic = ptr[4];
} else {
if (length != 4)
return -EINVAL;
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment