aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2015-10-15 13:28:44 +0200
committerHans Verkuil <hans.verkuil@cisco.com>2016-02-06 11:40:41 +0100
commit3a133cf8d9cd64b9e2bb3b9af1895f3dbac53952 (patch)
tree1159835110faac9aec25f393d9424292a96a7c76
parent23d1021ee79084e63f964f064d40e79615c793ae (diff)
hdmi: add missing NTSC VBI InfoFrame supportinfoframe
Add support for the NTSC VBI InfoFrame as specified by the CEA-861-F standard. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
-rw-r--r--drivers/video/hdmi.c120
-rw-r--r--include/linux/hdmi.h16
2 files changed, 135 insertions, 1 deletions
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 34c0f3c73b9b..9fab25a58d3e 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -305,6 +305,61 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
/**
+ * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI ntsc_vbi infoframe
+ * @frame: HDMI ntsc_vbi infoframe
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame)
+{
+ memset(frame, 0, sizeof(*frame));
+
+ frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
+ frame->version = 1;
+ frame->length = HDMI_NTSC_VBI_INFOFRAME_SIZE;
+
+ return 0;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack() - write HDMI audio infoframe to binary buffer
+ * @frame: HDMI ntsc_vbi infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
+ void *buffer, size_t size)
+{
+ u8 *ptr = buffer;
+ size_t length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+ if (size < length)
+ return -ENOSPC;
+
+ memset(buffer, 0, size);
+
+ ptr[0] = frame->type;
+ ptr[1] = frame->version;
+ ptr[2] = frame->length;
+ ptr[3] = 0; /* checksum */
+ memcpy(ptr + 4, frame->data, frame->length);
+
+ hdmi_infoframe_set_checksum(buffer, length);
+
+ return length;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
+
+/**
* hdmi_vendor_infoframe_init() - initialize an HDMI vendor infoframe
* @frame: HDMI vendor infoframe
*
@@ -515,6 +570,9 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
case HDMI_INFOFRAME_TYPE_AUDIO:
length = hdmi_audio_infoframe_pack(&frame->audio, buffer, size);
break;
+ case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+ length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi, buffer, size);
+ break;
case HDMI_INFOFRAME_TYPE_DYNRM:
length = hdmi_dynrm_infoframe_pack(&frame->dynrm, buffer, size);
break;
@@ -544,6 +602,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
return "Source Product Description (SPD)";
case HDMI_INFOFRAME_TYPE_AUDIO:
return "Audio";
+ case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+ return "NTSC VBI";
case HDMI_INFOFRAME_TYPE_DYNRM:
return "Dynamic Range and Mastering";
}
@@ -1000,6 +1060,22 @@ static void hdmi_audio_infoframe_log(const char *level,
frame->downmix_inhibit ? "Yes" : "No");
}
+/**
+ * hdmi_ntsc_vbi_infoframe_log() - log info of HDMI NTSC VBI infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI NTSC VBI infoframe
+ */
+static void hdmi_ntsc_vbi_infoframe_log(const char *level,
+ struct device *dev,
+ struct hdmi_ntsc_vbi_infoframe *frame)
+{
+ hdmi_infoframe_log_header(level, dev,
+ (struct hdmi_any_infoframe *)frame);
+
+ hdmi_log(" VBI payload: %*ph\n", frame->length, frame->data);
+}
+
static const char *
hdmi_dynrm_eotf_get_name(enum hdmi_dynrm_eotf eotf)
{
@@ -1157,6 +1233,9 @@ void hdmi_infoframe_log(const char *level,
case HDMI_INFOFRAME_TYPE_AUDIO:
hdmi_audio_infoframe_log(level, dev, &frame->audio);
break;
+ case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+ hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
+ break;
case HDMI_INFOFRAME_TYPE_DYNRM:
hdmi_dynrm_infoframe_log(level, dev, &frame->dynrm);
break;
@@ -1322,6 +1401,44 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
}
/**
+ * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI NTSC VBI infoframe
+ * @buffer: source buffer
+ * @frame: HDMI NTSC VBI infoframe
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI NTSC VBI information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_ntsc_vbi_infoframe_unpack(struct hdmi_ntsc_vbi_infoframe *frame,
+ void *buffer)
+{
+ u8 *ptr = buffer;
+ int ret;
+
+ if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+ ptr[1] != 1 ||
+ ptr[2] > HDMI_NTSC_VBI_INFOFRAME_SIZE) {
+ return -EINVAL;
+ }
+
+ if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_HEADER_SIZE + ptr[2]) != 0)
+ return -EINVAL;
+
+ ret = hdmi_ntsc_vbi_infoframe_init(frame);
+ if (ret)
+ return ret;
+
+ frame->length = ptr[2];
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+ memcpy(frame->data, ptr, frame->length);
+
+ return 0;
+}
+
+/**
* hdmi_dynrm_infoframe_unpack() - unpack binary buffer to a HDMI DYNRM infoframe
* @buffer: source buffer
* @frame: HDMI Dynamic Range and Mastering infoframe
@@ -1465,6 +1582,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
case HDMI_INFOFRAME_TYPE_AUDIO:
ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
break;
+ case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+ ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer);
+ break;
case HDMI_INFOFRAME_TYPE_DYNRM:
ret = hdmi_dynrm_infoframe_unpack(&frame->dynrm, buffer);
break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 579dc4f32e83..e969e58df474 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -32,6 +32,7 @@ enum hdmi_infoframe_type {
HDMI_INFOFRAME_TYPE_AVI = 0x82,
HDMI_INFOFRAME_TYPE_SPD = 0x83,
HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
+ HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
/*
* CEA-861.3: Dynamic Range and Mastering. And yes, I decided
* against calling it DRM :-)
@@ -44,6 +45,7 @@ enum hdmi_infoframe_type {
#define HDMI_AVI_INFOFRAME_SIZE 13
#define HDMI_SPD_INFOFRAME_SIZE 25
#define HDMI_AUDIO_INFOFRAME_SIZE 10
+#define HDMI_NTSC_VBI_INFOFRAME_SIZE 27
#define HDMI_DYNRM_INFOFRAME_SIZE 26
#define HDMI_INFOFRAME_SIZE(type) \
@@ -304,13 +306,23 @@ struct hdmi_audio_infoframe {
u32 channel_index;
};
bool downmix_inhibit;
-
};
int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
void *buffer, size_t size);
+struct hdmi_ntsc_vbi_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ unsigned char data[HDMI_NTSC_VBI_INFOFRAME_SIZE];
+};
+
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame);
+ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
+ void *buffer, size_t size);
+
enum hdmi_dynrm_eotf {
HDMI_DYNRM_EOTF_TRAD_GAMMA_SDR,
HDMI_DYNRM_EOTF_TRAD_GAMMA_HDR,
@@ -391,6 +403,7 @@ union hdmi_vendor_any_infoframe {
* @spd: spd infoframe
* @vendor: union of all vendor infoframes
* @audio: audio infoframe
+ * @ntsc_vbi: NTSC VBI infoframe
* @dynrm: dynrm infoframe
*
* This is used by the generic pack function. This works since all infoframes
@@ -403,6 +416,7 @@ union hdmi_infoframe {
struct hdmi_spd_infoframe spd;
union hdmi_vendor_any_infoframe vendor;
struct hdmi_audio_infoframe audio;
+ struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
struct hdmi_dynrm_infoframe dynrm;
};

Privacy Policy