linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/18] drm/i915: Infoframe precompute/check
@ 2018-09-20 18:51 Ville Syrjala
  2018-09-20 18:51 ` [PATCH 01/18] video/hdmi: Constify 'buffer' to the unpack functions Ville Syrjala
                   ` (6 more replies)
  0 siblings, 7 replies; 26+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Series aimed at precomputing the HDMI infoframes, and we also get
better validation by reading them back out from the hardware and
comparing with the expected data.

Looks like I typed these up about a year ago. Might be time to
get them in before the anniversary ;)

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org

Ville Syrjälä (18):
  video/hdmi: Constify 'buffer' to the unpack functions
  video/hdmi: Pass buffer size to infoframe unpack functions
  video/hdmi: Constify infoframe passed to the log functions
  video/hdmi: Constify infoframe passed to the pack functions
  video/hdmi: Add an enum for HDMI packet types
  video/hdmi: Handle the MPEG Source infoframe
  video/hdmi: Handle the NTSC VBI infoframe
  drm/i915: Use memmove() for punching the hole into infoframes
  drm/i915: Pass intel_encoder to infoframe functions
  drm/i915: Add the missing HDMI gamut metadata packet stuff
  drm/i915: Return the mask of enabled infoframes from
    ->inforame_enabled()
  drm/i915: Store mask of enabled infoframes in the crtc state
  drm/i915: Precompute HDMI infoframes
  drm/i915: Read out HDMI infoframes
  drm/i915/sdvo: Precompute HDMI infoframes
  drm/i915/sdvo: Read out HDMI infoframes
  drm/i915: Check infoframe state in intel_pipe_config_compare()
  drm/i915: Include infoframes in the crtc state dump

 drivers/gpu/drm/i915/i915_reg.h      |    4 +-
 drivers/gpu/drm/i915/intel_ddi.c     |   27 +-
 drivers/gpu/drm/i915/intel_display.c |   74 ++-
 drivers/gpu/drm/i915/intel_drv.h     |   27 +-
 drivers/gpu/drm/i915/intel_hdmi.c    |  651 ++++++++++++++++-----
 drivers/gpu/drm/i915/intel_psr.c     |    3 +-
 drivers/gpu/drm/i915/intel_sdvo.c    |  150 ++++-
 drivers/media/i2c/adv7511.c          |    2 +-
 drivers/media/i2c/adv7604.c          |    2 +-
 drivers/media/i2c/adv7842.c          |    2 +-
 drivers/media/i2c/tc358743.c         |    2 +-
 drivers/media/i2c/tda1997x.c         |    4 +-
 drivers/video/hdmi.c                 | 1032 ++++++++++++++++++++++++++++++----
 include/linux/hdmi.h                 |   84 ++-
 14 files changed, 1786 insertions(+), 278 deletions(-)

-- 
2.16.4

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 01/18] video/hdmi: Constify 'buffer' to the unpack functions
  2018-09-20 18:51 [PATCH 00/18] drm/i915: Infoframe precompute/check Ville Syrjala
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-21  8:03   ` Hans Verkuil
  2018-09-20 18:51 ` [PATCH 02/18] video/hdmi: Pass buffer size to infoframe " Ville Syrjala
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 26+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The unpack functions just read from the passed in buffer,
so make it const.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 23 ++++++++++++-----------
 include/linux/hdmi.h |  3 ++-
 2 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 38716eb50408..65b915ea4936 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -31,7 +31,7 @@
 
 #define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
 
-static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
+static u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size)
 {
 	u8 csum = 0;
 	size_t i;
@@ -1016,9 +1016,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
-				     void *buffer)
+				     const void *buffer)
 {
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 	int ret;
 
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
@@ -1079,9 +1079,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
-				     void *buffer)
+				     const void *buffer)
 {
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 	int ret;
 
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
@@ -1117,9 +1117,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
-				       void *buffer)
+				       const void *buffer)
 {
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 	int ret;
 
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
@@ -1163,9 +1163,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
  */
 static int
 hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
-				 void *buffer)
+				 const void *buffer)
 {
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 	size_t length;
 	int ret;
 	u8 hdmi_video_format;
@@ -1234,10 +1234,11 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
  *
  * Returns 0 on success or a negative error code on failure.
  */
-int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
+			  const void *buffer)
 {
 	int ret;
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 
 	switch (ptr[0]) {
 	case HDMI_INFOFRAME_TYPE_AVI:
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index d271ff23984f..d3816170c062 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -332,7 +332,8 @@ union hdmi_infoframe {
 
 ssize_t
 hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
-int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer);
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
+			  const void *buffer);
 void hdmi_infoframe_log(const char *level, struct device *dev,
 			union hdmi_infoframe *frame);
 
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 02/18] video/hdmi: Pass buffer size to infoframe unpack functions
  2018-09-20 18:51 [PATCH 00/18] drm/i915: Infoframe precompute/check Ville Syrjala
  2018-09-20 18:51 ` [PATCH 01/18] video/hdmi: Constify 'buffer' to the unpack functions Ville Syrjala
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-21  8:06   ` Hans Verkuil
  2018-09-20 18:51 ` [PATCH 03/18] video/hdmi: Constify infoframe passed to the log functions Ville Syrjala
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 26+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

To make sure the infoframe unpack functions don't end up examining
stack garbage or oopsing, let's pass in the size of the buffer.

v2: Convert tda1997x.c as well (kbuild test robot)

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/media/i2c/adv7511.c  |  2 +-
 drivers/media/i2c/adv7604.c  |  2 +-
 drivers/media/i2c/adv7842.c  |  2 +-
 drivers/media/i2c/tc358743.c |  2 +-
 drivers/media/i2c/tda1997x.c |  4 ++--
 drivers/video/hdmi.c         | 51 ++++++++++++++++++++++++++++++++------------
 include/linux/hdmi.h         |  2 +-
 7 files changed, 44 insertions(+), 21 deletions(-)

diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 55c2ea0720d9..b85b181bbb6c 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -550,7 +550,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_
 	buffer[3] = 0;
 	buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
 
-	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
 		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
 		return;
 	}
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 668be2bca57a..2e7a28dbad4e 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -2418,7 +2418,7 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index,
 		buffer[i + 3] = infoframe_read(sd,
 				       adv76xx_cri[index].payload_addr + i);
 
-	if (hdmi_infoframe_unpack(frame, buffer) < 0) {
+	if (hdmi_infoframe_unpack(frame, buffer, sizeof(buffer)) < 0) {
 		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__,
 			 adv76xx_cri[index].desc);
 		return -ENOENT;
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 4f8fbdd00e35..2cfd03f929b2 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -2563,7 +2563,7 @@ static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infofr
 	for (i = 0; i < len; i++)
 		buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
 
-	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
 		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
 		return;
 	}
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 44c41933415a..519bf92508d5 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -444,7 +444,7 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
 
 	i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI));
 
-	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
 		v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__);
 		return;
 	}
diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
index d114ac5243ec..195a1fc74ee8 100644
--- a/drivers/media/i2c/tda1997x.c
+++ b/drivers/media/i2c/tda1997x.c
@@ -1253,7 +1253,7 @@ tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr)
 
 	/* read data */
 	len = io_readn(sd, addr, sizeof(buffer), buffer);
-	err = hdmi_infoframe_unpack(&frame, buffer);
+	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
 	if (err) {
 		v4l_err(state->client,
 			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
@@ -1928,7 +1928,7 @@ static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr)
 	/* read data */
 	len = io_readn(sd, addr, sizeof(buffer), buffer);
 	v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len);
-	err = hdmi_infoframe_unpack(&frame, buffer);
+	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
 	if (err) {
 		v4l_err(state->client,
 			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 65b915ea4936..b5d491014b0b 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -1005,8 +1005,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
 
 /**
  * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
- * @buffer: source buffer
  * @frame: HDMI AVI infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Auxiliary Video (AVI) information frame.
@@ -1016,11 +1017,14 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
-				     const void *buffer)
+				     const void *buffer, size_t size)
 {
 	const u8 *ptr = buffer;
 	int ret;
 
+	if (size < HDMI_INFOFRAME_SIZE(AVI))
+		return -EINVAL;
+
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
 	    ptr[1] != 2 ||
 	    ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
@@ -1068,8 +1072,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
 
 /**
  * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
- * @buffer: source buffer
  * @frame: HDMI SPD infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Source Product Description (SPD) information frame.
@@ -1079,11 +1084,14 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
-				     const void *buffer)
+				     const void *buffer, size_t size)
 {
 	const u8 *ptr = buffer;
 	int ret;
 
+	if (size < HDMI_INFOFRAME_SIZE(SPD))
+		return -EINVAL;
+
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
 	    ptr[1] != 1 ||
 	    ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
@@ -1106,8 +1114,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
 
 /**
  * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
- * @buffer: source buffer
  * @frame: HDMI Audio infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Audio information frame.
@@ -1117,11 +1126,14 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
-				       const void *buffer)
+				       const void *buffer, size_t size)
 {
 	const u8 *ptr = buffer;
 	int ret;
 
+	if (size < HDMI_INFOFRAME_SIZE(AUDIO))
+		return -EINVAL;
+
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
 	    ptr[1] != 1 ||
 	    ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
@@ -1151,8 +1163,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
 
 /**
  * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe
- * @buffer: source buffer
  * @frame: HDMI Vendor infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Vendor information frame.
@@ -1163,7 +1176,7 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
  */
 static int
 hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
-				 const void *buffer)
+				 const void *buffer, size_t size)
 {
 	const u8 *ptr = buffer;
 	size_t length;
@@ -1171,6 +1184,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 	u8 hdmi_video_format;
 	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
 
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
 	    ptr[1] != 1 ||
 	    (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
@@ -1178,6 +1194,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 
 	length = ptr[2];
 
+	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
+		return -EINVAL;
+
 	if (hdmi_infoframe_checksum(buffer,
 				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
 		return -EINVAL;
@@ -1224,8 +1243,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
- * @buffer: source buffer
  * @frame: HDMI infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary buffer @buffer into a structured
  * @frame of a HDMI infoframe.
@@ -1235,23 +1255,26 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
-			  const void *buffer)
+			  const void *buffer, size_t size)
 {
 	int ret;
 	const u8 *ptr = buffer;
 
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+
 	switch (ptr[0]) {
 	case HDMI_INFOFRAME_TYPE_AVI:
-		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer);
+		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size);
 		break;
 	case HDMI_INFOFRAME_TYPE_SPD:
-		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer);
+		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size);
 		break;
 	case HDMI_INFOFRAME_TYPE_AUDIO:
-		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
+		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size);
 		break;
 	case HDMI_INFOFRAME_TYPE_VENDOR:
-		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer);
+		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
 		break;
 	default:
 		ret = -EINVAL;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index d3816170c062..a577d4ae2570 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -333,7 +333,7 @@ union hdmi_infoframe {
 ssize_t
 hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
-			  const void *buffer);
+			  const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
 			union hdmi_infoframe *frame);
 
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 03/18] video/hdmi: Constify infoframe passed to the log functions
  2018-09-20 18:51 [PATCH 00/18] drm/i915: Infoframe precompute/check Ville Syrjala
  2018-09-20 18:51 ` [PATCH 01/18] video/hdmi: Constify 'buffer' to the unpack functions Ville Syrjala
  2018-09-20 18:51 ` [PATCH 02/18] video/hdmi: Pass buffer size to infoframe " Ville Syrjala
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-21  8:06   ` Hans Verkuil
  2018-09-20 18:51 ` [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions Ville Syrjala
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 26+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The log functions don't modify the passed in infoframe so make it const.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 22 +++++++++++-----------
 include/linux/hdmi.h |  2 +-
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index b5d491014b0b..53e7ee2c83fc 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -471,7 +471,7 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 
 static void hdmi_infoframe_log_header(const char *level,
 				      struct device *dev,
-				      struct hdmi_any_infoframe *frame)
+				      const struct hdmi_any_infoframe *frame)
 {
 	hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
 		hdmi_infoframe_type_get_name(frame->type),
@@ -673,10 +673,10 @@ hdmi_content_type_get_name(enum hdmi_content_type content_type)
  */
 static void hdmi_avi_infoframe_log(const char *level,
 				   struct device *dev,
-				   struct hdmi_avi_infoframe *frame)
+				   const struct hdmi_avi_infoframe *frame)
 {
 	hdmi_infoframe_log_header(level, dev,
-				  (struct hdmi_any_infoframe *)frame);
+				  (const struct hdmi_any_infoframe *)frame);
 
 	hdmi_log("    colorspace: %s\n",
 			hdmi_colorspace_get_name(frame->colorspace));
@@ -750,12 +750,12 @@ static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
  */
 static void hdmi_spd_infoframe_log(const char *level,
 				   struct device *dev,
-				   struct hdmi_spd_infoframe *frame)
+				   const struct hdmi_spd_infoframe *frame)
 {
 	u8 buf[17];
 
 	hdmi_infoframe_log_header(level, dev,
-				  (struct hdmi_any_infoframe *)frame);
+				  (const struct hdmi_any_infoframe *)frame);
 
 	memset(buf, 0, sizeof(buf));
 
@@ -886,10 +886,10 @@ hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
  */
 static void hdmi_audio_infoframe_log(const char *level,
 				     struct device *dev,
-				     struct hdmi_audio_infoframe *frame)
+				     const struct hdmi_audio_infoframe *frame)
 {
 	hdmi_infoframe_log_header(level, dev,
-				  (struct hdmi_any_infoframe *)frame);
+				  (const struct hdmi_any_infoframe *)frame);
 
 	if (frame->channels)
 		hdmi_log("    channels: %u\n", frame->channels - 1);
@@ -949,12 +949,12 @@ hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
 static void
 hdmi_vendor_any_infoframe_log(const char *level,
 			      struct device *dev,
-			      union hdmi_vendor_any_infoframe *frame)
+			      const union hdmi_vendor_any_infoframe *frame)
 {
-	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
+	const struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
 
 	hdmi_infoframe_log_header(level, dev,
-				  (struct hdmi_any_infoframe *)frame);
+				  (const struct hdmi_any_infoframe *)frame);
 
 	if (frame->any.oui != HDMI_IEEE_OUI) {
 		hdmi_log("    not a HDMI vendor infoframe\n");
@@ -984,7 +984,7 @@ hdmi_vendor_any_infoframe_log(const char *level,
  */
 void hdmi_infoframe_log(const char *level,
 			struct device *dev,
-			union hdmi_infoframe *frame)
+			const union hdmi_infoframe *frame)
 {
 	switch (frame->any.type) {
 	case HDMI_INFOFRAME_TYPE_AVI:
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index a577d4ae2570..bce1abb1fe57 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -335,6 +335,6 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 			  const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
-			union hdmi_infoframe *frame);
+			const union hdmi_infoframe *frame);
 
 #endif /* _DRM_HDMI_H */
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions
  2018-09-20 18:51 [PATCH 00/18] drm/i915: Infoframe precompute/check Ville Syrjala
                   ` (2 preceding siblings ...)
  2018-09-20 18:51 ` [PATCH 03/18] video/hdmi: Constify infoframe passed to the log functions Ville Syrjala
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-21  8:24   ` Hans Verkuil
  2018-09-21 14:33   ` [PATCH v3 " Ville Syrjala
  2018-09-20 18:51 ` [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types Ville Syrjala
                   ` (2 subsequent siblings)
  6 siblings, 2 replies; 26+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Let's make the infoframe pack functions usable with a const infoframe
structure. This allows us to precompute the infoframe earlier, and still
pack it later when we're no longer allowed to modify the structure.
So now we end up with a _check()+_pack_only() or _pack() functions
depending on whether you want to precompute the infoframes or not.
The names aren't greate but I was lazy and didn't want to change all the
drivers.

v2: Deal with exynos churn
    Actually export the new funcs

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
 include/linux/hdmi.h |  19 ++-
 2 files changed, 416 insertions(+), 28 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 53e7ee2c83fc..9507f668a569 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_avi_infoframe_init);
 
+static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
+	    frame->version != 2 ||
+	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
+ * hdmi_avi_infoframe_check() - Check and check a HDMI AVI infoframe
+ * @frame: HDMI AVI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
+{
+	return hdmi_avi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_avi_infoframe_check);
+
+/**
+ * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
  * @frame: HDMI AVI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
-				size_t size)
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+				     void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_avi_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
 	if (size < length)
 		return -ENOSPC;
 
-	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
-		return -EINVAL;
-
 	memset(buffer, 0, size);
 
 	ptr[0] = frame->type;
@@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
+
+/**
+ * hdmi_avi_infoframe_pack() - Check and check a HDMI AVI infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI AVI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which 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_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
+				void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_avi_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
 
 /**
@@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 }
 EXPORT_SYMBOL(hdmi_spd_infoframe_init);
 
+static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
+ * hdmi_spd_infoframe_check() - Check and check a HDMI SPD infoframe
+ * @frame: HDMI SPD infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
+{
+	return hdmi_spd_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_spd_infoframe_check);
+
+/**
+ * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
  * @frame: HDMI SPD infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
-				size_t size)
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+				     void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_spd_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
+
+/**
+ * hdmi_spd_infoframe_pack() - Check and check a HDMI SPD infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI SPD infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which 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_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
+				void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_spd_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
 
 /**
@@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_audio_infoframe_init);
 
+static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_audio_infoframe_check() - Check and check a HDMI audio infoframe
+ * @frame: HDMI audio infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
+{
+	return hdmi_audio_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_check);
+
 /**
- * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
+ * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
  * @frame: HDMI audio infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
-				  void *buffer, size_t size)
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+				       void *buffer, size_t size)
 {
 	unsigned char channels;
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_audio_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
+
+/**
+ * hdmi_audio_infoframe_pack() - Check and check a HDMI Audio infoframe,
+ *                               and write it to binary buffer
+ * @frame: HDMI Audio infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which 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_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
+				  void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_audio_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
 
 /**
@@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
 	 * value
 	 */
 	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
+	frame->length = 4;
 
 	return 0;
 }
@@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
 		return 4;
 }
 
+static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->version != 1 ||
+	    frame->oui != HDMI_IEEE_OUI)
+		return -EINVAL;
+
+	/* only one of those can be supplied */
+	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+		return -EINVAL;
+
+	if (frame->length != hdmi_vendor_infoframe_length(frame))
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
+ * hdmi_vendor_infoframe_check() - Check and check a HDMI vendor infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
+{
+	frame->length = hdmi_vendor_infoframe_length(frame);
+
+	return hdmi_vendor_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
+
+/**
+ * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
-				 void *buffer, size_t size)
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+					void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
 
-	/* only one of those can be supplied */
-	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
-		return -EINVAL;
-
-	frame->length = hdmi_vendor_infoframe_length(frame);
+	ret = hdmi_vendor_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
+
+/**
+ * hdmi_vendor_infoframe_pack() - Check and check a HDMI Vendor infoframe,
+ *                                and write it to binary buffer
+ * @frame: HDMI Vendor infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which 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_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
+				   void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_vendor_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
 
+static int
+hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
+{
+	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->any.version != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
 /*
- * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
+ * hdmi_vendor_any_infoframe_check() - check and check a vendor infoframe
+ */
+static int
+hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
+{
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	/* we only know about HDMI vendor infoframes */
+	if (frame->any.oui != HDMI_IEEE_OUI)
+		return -EINVAL;
+
+	return hdmi_vendor_infoframe_check(&frame->hdmi);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
  */
 static ssize_t
-hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
-			   void *buffer, size_t size)
+hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
+				    void *buffer, size_t size)
 {
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
 	/* we only know about HDMI vendor infoframes */
 	if (frame->any.oui != HDMI_IEEE_OUI)
 		return -EINVAL;
 
-	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
+	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack() - check and check a vendor infoframe,
+ *                                              and write it to binary buffer
+ */
+static ssize_t
+hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
+			       void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
+}
+
+/**
+ * hdmi_infoframe_check() - Check check a HDMI infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int
+hdmi_infoframe_check(union hdmi_infoframe *frame)
+{
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		return hdmi_avi_infoframe_check(&frame->avi);
+	case HDMI_INFOFRAME_TYPE_SPD:
+		return hdmi_spd_infoframe_check(&frame->spd);
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		return hdmi_audio_infoframe_check(&frame->audio);
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		return hdmi_vendor_any_infoframe_check(&frame->vendor);
+	default:
+		WARN(1, "Bad infoframe type %d\n", frame->any.type);
+		return -EINVAL;
+	}
 }
+EXPORT_SYMBOL(hdmi_infoframe_check);
 
 /**
- * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
+ * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
  * error code on failure.
  */
 ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
+hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
+{
+	ssize_t length;
+
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		length = hdmi_avi_infoframe_pack_only(&frame->avi,
+						      buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_SPD:
+		length = hdmi_spd_infoframe_pack_only(&frame->spd,
+						      buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		length = hdmi_audio_infoframe_pack_only(&frame->audio,
+							buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
+							     buffer, size);
+		break;
+	default:
+		WARN(1, "Bad infoframe type %d\n", frame->any.type);
+		length = -EINVAL;
+	}
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_infoframe_pack_only);
+
+/**
+ * hdmi_infoframe_pack() - Check check a HDMI infoframe,
+ *                         and write it to binary buffer
+ * @frame: HDMI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which 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_infoframe_pack(union hdmi_infoframe *frame,
+		    void *buffer, size_t size)
 {
 	ssize_t length;
 
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index bce1abb1fe57..c76b50a48e48 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
 int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
 ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
 				size_t size);
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+				     void *buffer, size_t size);
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
 
 enum hdmi_spd_sdi {
 	HDMI_SPD_SDI_UNKNOWN,
@@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 			    const char *vendor, const char *product);
 ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 				size_t size);
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+				     void *buffer, size_t size);
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
 
 enum hdmi_audio_coding_type {
 	HDMI_AUDIO_CODING_TYPE_STREAM,
@@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
 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);
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+				       void *buffer, size_t size);
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
 
 enum hdmi_3d_structure {
 	HDMI_3D_STRUCTURE_INVALID = -1,
@@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
 int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
 ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 				   void *buffer, size_t size);
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+					void *buffer, size_t size);
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
 
 union hdmi_vendor_any_infoframe {
 	struct {
@@ -330,8 +342,11 @@ union hdmi_infoframe {
 	struct hdmi_audio_infoframe audio;
 };
 
-ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
+ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
+			    size_t size);
+ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
+				 void *buffer, size_t size);
+int hdmi_infoframe_check(union hdmi_infoframe *frame);
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 			  const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
  2018-09-20 18:51 [PATCH 00/18] drm/i915: Infoframe precompute/check Ville Syrjala
                   ` (3 preceding siblings ...)
  2018-09-20 18:51 ` [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions Ville Syrjala
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-21  8:41   ` Hans Verkuil
  2018-09-20 18:51 ` [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe Ville Syrjala
  2018-09-20 18:51 ` [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe Ville Syrjala
  6 siblings, 1 reply; 26+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

We'll be wanting to send more than just infoframes over HDMI. So add an
enum for other packet types.

TODO: Maybe just include the infoframe types in the packet type enum
      and get rid of the infoframe type enum?

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 include/linux/hdmi.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index c76b50a48e48..80521d9591a1 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -27,6 +27,21 @@
 #include <linux/types.h>
 #include <linux/device.h>
 
+enum hdmi_packet_type {
+	HDMI_PACKET_TYPE_NULL = 0x00,
+	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
+	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
+	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
+	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
+	HDMI_PACKET_TYPE_ISRC1 = 0x05,
+	HDMI_PACKET_TYPE_ISRC2 = 0x06,
+	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
+	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
+	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
+	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
+	/* + enum hdmi_infoframe_type */
+};
+
 enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
 	HDMI_INFOFRAME_TYPE_AVI = 0x82,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe
  2018-09-20 18:51 [PATCH 00/18] drm/i915: Infoframe precompute/check Ville Syrjala
                   ` (4 preceding siblings ...)
  2018-09-20 18:51 ` [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types Ville Syrjala
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-21  8:28   ` Hans Verkuil
  2018-09-21 15:09   ` [PATCH v2 " Ville Syrjala
  2018-09-20 18:51 ` [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe Ville Syrjala
  6 siblings, 2 replies; 26+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the code to deal with the MPEG source infoframe.

Blindly typed from the spec, and totally untested.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |  27 ++++++
 2 files changed, 256 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 9507f668a569..3d24c7746c51 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -706,6 +706,131 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
 	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
 }
 
+/**
+ * hdmi_mpeg_source_infoframe_init() - initialize an HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame)
+{
+	memset(frame, 0, sizeof(*frame));
+
+	frame->type = HDMI_INFOFRAME_TYPE_MPEG_SOURCE;
+	frame->version = 1;
+	frame->length = HDMI_MPEG_SOURCE_INFOFRAME_SIZE;
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_init);
+
+static int hdmi_mpeg_source_infoframe_check_only(const struct hdmi_mpeg_source_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_MPEG_SOURCE_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_mpeg_source_infoframe_check() - Check and check a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame)
+{
+	return hdmi_mpeg_source_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_check);
+
+/**
+ * hdmi_mpeg_source_infoframe_pack_only() - write HDMI MPEG Source infoframe to binary buffer
+ * @frame: HDMI MPEG Source 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_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
+					     void *buffer, size_t size)
+{
+	u8 *ptr = buffer;
+	size_t length;
+	int ret;
+
+	ret = hdmi_mpeg_source_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	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 */
+
+	/* start infoframe payload */
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	ptr[0] = frame->mpeg_bit_rate >> 0;
+	ptr[1] = frame->mpeg_bit_rate >> 8;
+	ptr[2] = frame->mpeg_bit_rate >> 16;
+	ptr[3] = frame->mpeg_bit_rate >> 24;
+	ptr[4] = (frame->field_repeat << 4) | frame->mpeg_frame;
+
+	hdmi_infoframe_set_checksum(buffer, length);
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack_only);
+
+/**
+ * hdmi_mpeg_source_infoframe_pack() - Check and check a HDMI MPEG Source infoframe,
+ *                                     and write it to binary buffer
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which 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_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
+					void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_mpeg_source_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_mpeg_source_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
+
 /**
  * hdmi_infoframe_check() - Check check a HDMI infoframe
  * @frame: HDMI infoframe
@@ -727,6 +852,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
 		return hdmi_audio_infoframe_check(&frame->audio);
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		return hdmi_vendor_any_infoframe_check(&frame->vendor);
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		return -EINVAL;
@@ -770,6 +897,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
 		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
 							     buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
+							      buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -816,6 +947,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
 		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
 							buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
+							 buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -838,6 +973,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_MPEG_SOURCE:
+		return "MPEG Source";
 	}
 	return "Reserved";
 }
@@ -1349,6 +1486,46 @@ hdmi_vendor_any_infoframe_log(const char *level,
 	}
 }
 
+static const char *
+hdmi_mpeg_frame_get_name(enum hdmi_mpeg_frame frame)
+{
+	if (frame < 0 || frame > 3)
+		return "invalid";
+
+	switch (frame) {
+	case HDMI_MPEG_FRAME_UNKNOWN:
+		return "Unknown";
+	case HDMI_MPEG_FRAME_I_PICTURE:
+		return "I Picture";
+	case HDMI_MPEG_FRAME_B_PICTURE:
+		return "B Picture";
+	case HDMI_MPEG_FRAME_P_PICTURE:
+		return "P Picture";
+	}
+	return "Reserved";
+}
+
+/**
+ * hdmi_mpeg_source_infoframe_log() - log info of HDMI MPEG Source infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI MPEG Source infoframe
+ */
+static void hdmi_mpeg_source_infoframe_log(const char *level,
+					   struct device *dev,
+					   const struct hdmi_mpeg_source_infoframe *frame)
+{
+	hdmi_infoframe_log_header(level, dev,
+				  (const struct hdmi_any_infoframe *)frame);
+
+	hdmi_log("    MPEG bit rate: %d Hz\n",
+		 frame->mpeg_bit_rate);
+	hdmi_log("    MPEG frame: %s\n",
+		 hdmi_mpeg_frame_get_name(frame->mpeg_frame));
+	hdmi_log("    field repeat: %s\n",
+		 frame->field_repeat ? "Yes" : "No");
+}
+
 /**
  * hdmi_infoframe_log() - log info of HDMI infoframe
  * @level: logging level
@@ -1372,6 +1549,9 @@ void hdmi_infoframe_log(const char *level,
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
+		break;
 	}
 }
 EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1614,6 +1794,52 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 	return 0;
 }
 
+/**
+ * hdmi_mpeg_source_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI MPEG Source 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_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *frame,
+					     const void *buffer, size_t size)
+{
+	const u8 *ptr = buffer;
+	int ret;
+
+	if (size < HDMI_INFOFRAME_SIZE(MPEG_SOURCE))
+		return -EINVAL;
+
+	if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
+	    ptr[1] != 1 ||
+	    ptr[2] != HDMI_MPEG_SOURCE_INFOFRAME_SIZE) {
+		return -EINVAL;
+	}
+
+	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG_SOURCE)) != 0)
+		return -EINVAL;
+
+	ret = hdmi_mpeg_source_infoframe_init(frame);
+	if (ret)
+		return ret;
+
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	frame->mpeg_bit_rate =
+		(ptr[0] << 0) | (ptr[1] << 8) |
+		(ptr[2] << 16) | (ptr[3] << 24);
+	frame->mpeg_frame = ptr[4] & 0x3;
+	frame->field_repeat = ptr[4] & 0x10;
+
+	return 0;
+}
+
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
  * @frame: HDMI infoframe
@@ -1649,6 +1875,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 80521d9591a1..2c9322f7538d 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_AVI = 0x82,
 	HDMI_INFOFRAME_TYPE_SPD = 0x83,
 	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
+	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
 };
 
 #define HDMI_IEEE_OUI 0x000c03
@@ -55,6 +56,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_MPEG_SOURCE_INFOFRAME_SIZE  10
 
 #define HDMI_INFOFRAME_SIZE(type)	\
 	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
@@ -337,6 +339,29 @@ union hdmi_vendor_any_infoframe {
 	struct hdmi_vendor_infoframe hdmi;
 };
 
+enum hdmi_mpeg_frame {
+	HDMI_MPEG_FRAME_UNKNOWN,
+	HDMI_MPEG_FRAME_I_PICTURE,
+	HDMI_MPEG_FRAME_B_PICTURE,
+	HDMI_MPEG_FRAME_P_PICTURE,
+};
+
+struct hdmi_mpeg_source_infoframe {
+	enum hdmi_infoframe_type type;
+	unsigned char version;
+	unsigned char length;
+	unsigned int mpeg_bit_rate;
+	enum hdmi_mpeg_frame mpeg_frame;
+	bool field_repeat;
+};
+
+int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame);
+ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
+					void *buffer, size_t size);
+ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
+					     void *buffer, size_t size);
+int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
+
 /**
  * union hdmi_infoframe - overall union of all abstract infoframe representations
  * @any: generic infoframe
@@ -344,6 +369,7 @@ union hdmi_vendor_any_infoframe {
  * @spd: spd infoframe
  * @vendor: union of all vendor infoframes
  * @audio: audio infoframe
+ * @mpeg_source: mpeg source infoframe
  *
  * This is used by the generic pack function. This works since all infoframes
  * have the same header which also indicates which type of infoframe should be
@@ -355,6 +381,7 @@ union hdmi_infoframe {
 	struct hdmi_spd_infoframe spd;
 	union hdmi_vendor_any_infoframe vendor;
 	struct hdmi_audio_infoframe audio;
+	struct hdmi_mpeg_source_infoframe mpeg_source;
 };
 
 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe
  2018-09-20 18:51 [PATCH 00/18] drm/i915: Infoframe precompute/check Ville Syrjala
                   ` (5 preceding siblings ...)
  2018-09-20 18:51 ` [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe Ville Syrjala
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-21  8:30   ` Hans Verkuil
  2018-09-21 15:10   ` [PATCH v2 " Ville Syrjala
  6 siblings, 2 replies; 26+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the code to deal with the NTSC VBI infoframe.

I decided against parsing the PES_data_field and just leave
it as an opaque blob, just dumping it out as hex in the log.

Blindly typed from the spec, and totally untested.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |  18 +++++
 2 files changed, 226 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 3d24c7746c51..3c320d69fa0a 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -831,6 +831,139 @@ ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame
 }
 EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
 
+/**
+ * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI NTSC VBI infoframe
+ * @frame: HDMI NTSC VBI infoframe
+ * @pes_data_field: ANSI/SCTE 127 PES_data_field
+ * @length: ANSI/SCTE 127 PES_data_field length
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
+				 const void *pes_data_field,
+				 size_t length)
+{
+	if (length < 1 || length > 27)
+		return -EINVAL;
+
+	memset(frame, 0, sizeof(*frame));
+
+	frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
+	frame->version = 1;
+	frame->length = length;
+
+	memcpy(frame->pes_data_field, pes_data_field, length);
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
+
+static int hdmi_ntsc_vbi_infoframe_check_only(const struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+	    frame->version != 1 ||
+	    frame->length < 1 || frame->length > 27)
+		return -EINVAL;
+
+	if (frame->pes_data_field[0] != 0x99)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_ntsc_vbi_infoframe_check() - Check and check a HDMI NTSC VBI infoframe
+ * @frame: HDMI NTSC VBI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	return hdmi_ntsc_vbi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_check);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack_only() - write HDMI NTSC VBI 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_only(const struct hdmi_ntsc_vbi_infoframe *frame,
+					  void *buffer, size_t size)
+{
+	u8 *ptr = buffer;
+	size_t length;
+	int ret;
+
+	ret = hdmi_ntsc_vbi_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	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 */
+
+	/* start infoframe payload */
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	memcpy(ptr, frame->pes_data_field, frame->length);
+
+	hdmi_infoframe_set_checksum(buffer, length);
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack_only);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack() - Check and check a HDMI NTSC VBI infoframe,
+ *                                  and write it to binary buffer
+ * @frame: HDMI NTSC VBI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which 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)
+{
+	int ret;
+
+	ret = hdmi_ntsc_vbi_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_ntsc_vbi_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
+
 /**
  * hdmi_infoframe_check() - Check check a HDMI infoframe
  * @frame: HDMI infoframe
@@ -854,6 +987,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
 		return hdmi_vendor_any_infoframe_check(&frame->vendor);
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		return -EINVAL;
@@ -901,6 +1036,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
 		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
 							      buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		length = hdmi_ntsc_vbi_infoframe_pack_only(&frame->ntsc_vbi,
+							   buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -951,6 +1090,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
 		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
 							 buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi,
+						      buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -975,6 +1118,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 		return "Audio";
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		return "MPEG Source";
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		return "NTSC VBI";
 	}
 	return "Reserved";
 }
@@ -1526,6 +1671,22 @@ static void hdmi_mpeg_source_infoframe_log(const char *level,
 		 frame->field_repeat ? "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,
+					const struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	hdmi_infoframe_log_header(level, dev,
+				  (const struct hdmi_any_infoframe *)frame);
+
+	hdmi_log("    %*ph\n", frame->length, frame->pes_data_field);
+}
+
 /**
  * hdmi_infoframe_log() - log info of HDMI infoframe
  * @level: logging level
@@ -1552,6 +1713,9 @@ void hdmi_infoframe_log(const char *level,
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
+		break;
 	}
 }
 EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1840,6 +2004,47 @@ static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *
 	return 0;
 }
 
+/**
+ * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI MPEG Source 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,
+					  const void *buffer, size_t size)
+{
+	const u8 *ptr = buffer;
+	size_t length;
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+
+	if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+	    ptr[1] != 1 ||
+	    ptr[2] < 1 || ptr[2] > 27)
+		return -EINVAL;
+
+	length = ptr[2];
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
+		return -EINVAL;
+
+	if (hdmi_infoframe_checksum(buffer,
+				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
+		return -EINVAL;
+
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	return hdmi_ntsc_vbi_infoframe_init(frame, ptr, length);
+}
+
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
  * @frame: HDMI infoframe
@@ -1878,6 +2083,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer, size);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 2c9322f7538d..3821516b336c 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -48,6 +48,7 @@ enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_SPD = 0x83,
 	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
 	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
+	HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
 };
 
 #define HDMI_IEEE_OUI 0x000c03
@@ -362,6 +363,21 @@ ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infof
 					     void *buffer, size_t size);
 int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
 
+struct hdmi_ntsc_vbi_infoframe {
+	enum hdmi_infoframe_type type;
+	unsigned char version;
+	unsigned char length;
+	unsigned char pes_data_field[27];
+};
+
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
+				 const void *pes_data_field, size_t length);
+ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
+				     void *buffer, size_t size);
+ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
+					  void *buffer, size_t size);
+int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame);
+
 /**
  * union hdmi_infoframe - overall union of all abstract infoframe representations
  * @any: generic infoframe
@@ -370,6 +386,7 @@ int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
  * @vendor: union of all vendor infoframes
  * @audio: audio infoframe
  * @mpeg_source: mpeg source infoframe
+ * @ntsc_vbi: ntsc vbi infoframe
  *
  * This is used by the generic pack function. This works since all infoframes
  * have the same header which also indicates which type of infoframe should be
@@ -382,6 +399,7 @@ union hdmi_infoframe {
 	union hdmi_vendor_any_infoframe vendor;
 	struct hdmi_audio_infoframe audio;
 	struct hdmi_mpeg_source_infoframe mpeg_source;
+	struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
 };
 
 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH 01/18] video/hdmi: Constify 'buffer' to the unpack functions
  2018-09-20 18:51 ` [PATCH 01/18] video/hdmi: Constify 'buffer' to the unpack functions Ville Syrjala
@ 2018-09-21  8:03   ` Hans Verkuil
  0 siblings, 0 replies; 26+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:03 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> The unpack functions just read from the passed in buffer,
> so make it const.
> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Thanks!

	Hans

> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 23 ++++++++++++-----------
>  include/linux/hdmi.h |  3 ++-
>  2 files changed, 14 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 38716eb50408..65b915ea4936 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -31,7 +31,7 @@
>  
>  #define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
>  
> -static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
> +static u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size)
>  {
>  	u8 csum = 0;
>  	size_t i;
> @@ -1016,9 +1016,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
> -				     void *buffer)
> +				     const void *buffer)
>  {
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  	int ret;
>  
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
> @@ -1079,9 +1079,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
> -				     void *buffer)
> +				     const void *buffer)
>  {
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  	int ret;
>  
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
> @@ -1117,9 +1117,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
> -				       void *buffer)
> +				       const void *buffer)
>  {
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  	int ret;
>  
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
> @@ -1163,9 +1163,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
>   */
>  static int
>  hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
> -				 void *buffer)
> +				 const void *buffer)
>  {
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  	size_t length;
>  	int ret;
>  	u8 hdmi_video_format;
> @@ -1234,10 +1234,11 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>   *
>   * Returns 0 on success or a negative error code on failure.
>   */
> -int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
> +int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> +			  const void *buffer)
>  {
>  	int ret;
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  
>  	switch (ptr[0]) {
>  	case HDMI_INFOFRAME_TYPE_AVI:
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index d271ff23984f..d3816170c062 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -332,7 +332,8 @@ union hdmi_infoframe {
>  
>  ssize_t
>  hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
> -int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer);
> +int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> +			  const void *buffer);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
>  			union hdmi_infoframe *frame);
>  
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 02/18] video/hdmi: Pass buffer size to infoframe unpack functions
  2018-09-20 18:51 ` [PATCH 02/18] video/hdmi: Pass buffer size to infoframe " Ville Syrjala
@ 2018-09-21  8:06   ` Hans Verkuil
  0 siblings, 0 replies; 26+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:06 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> To make sure the infoframe unpack functions don't end up examining
> stack garbage or oopsing, let's pass in the size of the buffer.
> 
> v2: Convert tda1997x.c as well (kbuild test robot)
> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Thanks,

	Hans

> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/media/i2c/adv7511.c  |  2 +-
>  drivers/media/i2c/adv7604.c  |  2 +-
>  drivers/media/i2c/adv7842.c  |  2 +-
>  drivers/media/i2c/tc358743.c |  2 +-
>  drivers/media/i2c/tda1997x.c |  4 ++--
>  drivers/video/hdmi.c         | 51 ++++++++++++++++++++++++++++++++------------
>  include/linux/hdmi.h         |  2 +-
>  7 files changed, 44 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
> index 55c2ea0720d9..b85b181bbb6c 100644
> --- a/drivers/media/i2c/adv7511.c
> +++ b/drivers/media/i2c/adv7511.c
> @@ -550,7 +550,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_
>  	buffer[3] = 0;
>  	buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
>  
> -	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
> +	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
>  		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
>  		return;
>  	}
> diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
> index 668be2bca57a..2e7a28dbad4e 100644
> --- a/drivers/media/i2c/adv7604.c
> +++ b/drivers/media/i2c/adv7604.c
> @@ -2418,7 +2418,7 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index,
>  		buffer[i + 3] = infoframe_read(sd,
>  				       adv76xx_cri[index].payload_addr + i);
>  
> -	if (hdmi_infoframe_unpack(frame, buffer) < 0) {
> +	if (hdmi_infoframe_unpack(frame, buffer, sizeof(buffer)) < 0) {
>  		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__,
>  			 adv76xx_cri[index].desc);
>  		return -ENOENT;
> diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
> index 4f8fbdd00e35..2cfd03f929b2 100644
> --- a/drivers/media/i2c/adv7842.c
> +++ b/drivers/media/i2c/adv7842.c
> @@ -2563,7 +2563,7 @@ static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infofr
>  	for (i = 0; i < len; i++)
>  		buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
>  
> -	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
> +	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
>  		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
>  		return;
>  	}
> diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
> index 44c41933415a..519bf92508d5 100644
> --- a/drivers/media/i2c/tc358743.c
> +++ b/drivers/media/i2c/tc358743.c
> @@ -444,7 +444,7 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
>  
>  	i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI));
>  
> -	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
> +	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
>  		v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__);
>  		return;
>  	}
> diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
> index d114ac5243ec..195a1fc74ee8 100644
> --- a/drivers/media/i2c/tda1997x.c
> +++ b/drivers/media/i2c/tda1997x.c
> @@ -1253,7 +1253,7 @@ tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr)
>  
>  	/* read data */
>  	len = io_readn(sd, addr, sizeof(buffer), buffer);
> -	err = hdmi_infoframe_unpack(&frame, buffer);
> +	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
>  	if (err) {
>  		v4l_err(state->client,
>  			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
> @@ -1928,7 +1928,7 @@ static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr)
>  	/* read data */
>  	len = io_readn(sd, addr, sizeof(buffer), buffer);
>  	v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len);
> -	err = hdmi_infoframe_unpack(&frame, buffer);
> +	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
>  	if (err) {
>  		v4l_err(state->client,
>  			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 65b915ea4936..b5d491014b0b 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -1005,8 +1005,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
>  
>  /**
>   * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
> - * @buffer: source buffer
>   * @frame: HDMI AVI infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary @buffer into a structured
>   * @frame of the HDMI Auxiliary Video (AVI) information frame.
> @@ -1016,11 +1017,14 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
> -				     const void *buffer)
> +				     const void *buffer, size_t size)
>  {
>  	const u8 *ptr = buffer;
>  	int ret;
>  
> +	if (size < HDMI_INFOFRAME_SIZE(AVI))
> +		return -EINVAL;
> +
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
>  	    ptr[1] != 2 ||
>  	    ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
> @@ -1068,8 +1072,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
>  
>  /**
>   * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
> - * @buffer: source buffer
>   * @frame: HDMI SPD infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary @buffer into a structured
>   * @frame of the HDMI Source Product Description (SPD) information frame.
> @@ -1079,11 +1084,14 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
> -				     const void *buffer)
> +				     const void *buffer, size_t size)
>  {
>  	const u8 *ptr = buffer;
>  	int ret;
>  
> +	if (size < HDMI_INFOFRAME_SIZE(SPD))
> +		return -EINVAL;
> +
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
>  	    ptr[1] != 1 ||
>  	    ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
> @@ -1106,8 +1114,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
>  
>  /**
>   * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
> - * @buffer: source buffer
>   * @frame: HDMI Audio infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary @buffer into a structured
>   * @frame of the HDMI Audio information frame.
> @@ -1117,11 +1126,14 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
> -				       const void *buffer)
> +				       const void *buffer, size_t size)
>  {
>  	const u8 *ptr = buffer;
>  	int ret;
>  
> +	if (size < HDMI_INFOFRAME_SIZE(AUDIO))
> +		return -EINVAL;
> +
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
>  	    ptr[1] != 1 ||
>  	    ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
> @@ -1151,8 +1163,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
>  
>  /**
>   * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe
> - * @buffer: source buffer
>   * @frame: HDMI Vendor infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary @buffer into a structured
>   * @frame of the HDMI Vendor information frame.
> @@ -1163,7 +1176,7 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
>   */
>  static int
>  hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
> -				 const void *buffer)
> +				 const void *buffer, size_t size)
>  {
>  	const u8 *ptr = buffer;
>  	size_t length;
> @@ -1171,6 +1184,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>  	u8 hdmi_video_format;
>  	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
>  
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE)
> +		return -EINVAL;
> +
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
>  	    ptr[1] != 1 ||
>  	    (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
> @@ -1178,6 +1194,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>  
>  	length = ptr[2];
>  
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
> +		return -EINVAL;
> +
>  	if (hdmi_infoframe_checksum(buffer,
>  				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
>  		return -EINVAL;
> @@ -1224,8 +1243,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>  
>  /**
>   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
> - * @buffer: source buffer
>   * @frame: HDMI infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary buffer @buffer into a structured
>   * @frame of a HDMI infoframe.
> @@ -1235,23 +1255,26 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> -			  const void *buffer)
> +			  const void *buffer, size_t size)
>  {
>  	int ret;
>  	const u8 *ptr = buffer;
>  
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE)
> +		return -EINVAL;
> +
>  	switch (ptr[0]) {
>  	case HDMI_INFOFRAME_TYPE_AVI:
> -		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer);
> +		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size);
>  		break;
>  	case HDMI_INFOFRAME_TYPE_SPD:
> -		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer);
> +		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size);
>  		break;
>  	case HDMI_INFOFRAME_TYPE_AUDIO:
> -		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
> +		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size);
>  		break;
>  	case HDMI_INFOFRAME_TYPE_VENDOR:
> -		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer);
> +		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
>  		break;
>  	default:
>  		ret = -EINVAL;
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index d3816170c062..a577d4ae2570 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -333,7 +333,7 @@ union hdmi_infoframe {
>  ssize_t
>  hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> -			  const void *buffer);
> +			  const void *buffer, size_t size);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
>  			union hdmi_infoframe *frame);
>  
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 03/18] video/hdmi: Constify infoframe passed to the log functions
  2018-09-20 18:51 ` [PATCH 03/18] video/hdmi: Constify infoframe passed to the log functions Ville Syrjala
@ 2018-09-21  8:06   ` Hans Verkuil
  0 siblings, 0 replies; 26+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:06 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> The log functions don't modify the passed in infoframe so make it const.
> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Thanks,

	Hans


> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 22 +++++++++++-----------
>  include/linux/hdmi.h |  2 +-
>  2 files changed, 12 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index b5d491014b0b..53e7ee2c83fc 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -471,7 +471,7 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
>  
>  static void hdmi_infoframe_log_header(const char *level,
>  				      struct device *dev,
> -				      struct hdmi_any_infoframe *frame)
> +				      const struct hdmi_any_infoframe *frame)
>  {
>  	hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
>  		hdmi_infoframe_type_get_name(frame->type),
> @@ -673,10 +673,10 @@ hdmi_content_type_get_name(enum hdmi_content_type content_type)
>   */
>  static void hdmi_avi_infoframe_log(const char *level,
>  				   struct device *dev,
> -				   struct hdmi_avi_infoframe *frame)
> +				   const struct hdmi_avi_infoframe *frame)
>  {
>  	hdmi_infoframe_log_header(level, dev,
> -				  (struct hdmi_any_infoframe *)frame);
> +				  (const struct hdmi_any_infoframe *)frame);
>  
>  	hdmi_log("    colorspace: %s\n",
>  			hdmi_colorspace_get_name(frame->colorspace));
> @@ -750,12 +750,12 @@ static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
>   */
>  static void hdmi_spd_infoframe_log(const char *level,
>  				   struct device *dev,
> -				   struct hdmi_spd_infoframe *frame)
> +				   const struct hdmi_spd_infoframe *frame)
>  {
>  	u8 buf[17];
>  
>  	hdmi_infoframe_log_header(level, dev,
> -				  (struct hdmi_any_infoframe *)frame);
> +				  (const struct hdmi_any_infoframe *)frame);
>  
>  	memset(buf, 0, sizeof(buf));
>  
> @@ -886,10 +886,10 @@ hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
>   */
>  static void hdmi_audio_infoframe_log(const char *level,
>  				     struct device *dev,
> -				     struct hdmi_audio_infoframe *frame)
> +				     const struct hdmi_audio_infoframe *frame)
>  {
>  	hdmi_infoframe_log_header(level, dev,
> -				  (struct hdmi_any_infoframe *)frame);
> +				  (const struct hdmi_any_infoframe *)frame);
>  
>  	if (frame->channels)
>  		hdmi_log("    channels: %u\n", frame->channels - 1);
> @@ -949,12 +949,12 @@ hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
>  static void
>  hdmi_vendor_any_infoframe_log(const char *level,
>  			      struct device *dev,
> -			      union hdmi_vendor_any_infoframe *frame)
> +			      const union hdmi_vendor_any_infoframe *frame)
>  {
> -	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
> +	const struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
>  
>  	hdmi_infoframe_log_header(level, dev,
> -				  (struct hdmi_any_infoframe *)frame);
> +				  (const struct hdmi_any_infoframe *)frame);
>  
>  	if (frame->any.oui != HDMI_IEEE_OUI) {
>  		hdmi_log("    not a HDMI vendor infoframe\n");
> @@ -984,7 +984,7 @@ hdmi_vendor_any_infoframe_log(const char *level,
>   */
>  void hdmi_infoframe_log(const char *level,
>  			struct device *dev,
> -			union hdmi_infoframe *frame)
> +			const union hdmi_infoframe *frame)
>  {
>  	switch (frame->any.type) {
>  	case HDMI_INFOFRAME_TYPE_AVI:
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index a577d4ae2570..bce1abb1fe57 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -335,6 +335,6 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  			  const void *buffer, size_t size);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
> -			union hdmi_infoframe *frame);
> +			const union hdmi_infoframe *frame);
>  
>  #endif /* _DRM_HDMI_H */
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions
  2018-09-20 18:51 ` [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions Ville Syrjala
@ 2018-09-21  8:24   ` Hans Verkuil
  2018-09-21 14:30     ` Ville Syrjälä
  2018-09-21 14:33   ` [PATCH v3 " Ville Syrjala
  1 sibling, 1 reply; 26+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:24 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Let's make the infoframe pack functions usable with a const infoframe
> structure. This allows us to precompute the infoframe earlier, and still
> pack it later when we're no longer allowed to modify the structure.
> So now we end up with a _check()+_pack_only() or _pack() functions
> depending on whether you want to precompute the infoframes or not.
> The names aren't greate but I was lazy and didn't want to change all the

greate -> great

> drivers.
> 
> v2: Deal with exynos churn
>     Actually export the new funcs
> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
>  include/linux/hdmi.h |  19 ++-
>  2 files changed, 416 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 53e7ee2c83fc..9507f668a569 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
>  }
>  EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>  
> +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
> +	    frame->version != 2 ||
> +	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
> + * hdmi_avi_infoframe_check() - Check and check a HDMI AVI infoframe

"Check and check"? This is repeated elsewhere as well (clearly copy-and-paste).

> + * @frame: HDMI AVI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
> +{
> +	return hdmi_avi_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_avi_infoframe_check);
> +
> +/**
> + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
>   * @frame: HDMI AVI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> -				size_t size)
> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> +				     void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_avi_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
>  	if (size < length)
>  		return -ENOSPC;
>  
> -	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> -		return -EINVAL;
> -
>  	memset(buffer, 0, size);
>  
>  	ptr[0] = frame->type;
> @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
> +
> +/**
> + * hdmi_avi_infoframe_pack() - Check and check a HDMI AVI infoframe,
> + *                             and write it to binary buffer
> + * @frame: HDMI AVI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information

which packs -> which it packs

Ditto elsewhere.

> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also

Also -> This function also

Ditto elsewhere.

> + * 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_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
> +				void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_avi_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
>  
>  /**
> @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>  }
>  EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>  
> +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
> + * hdmi_spd_infoframe_check() - Check and check a HDMI SPD infoframe
> + * @frame: HDMI SPD infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
> +{
> +	return hdmi_spd_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_spd_infoframe_check);
> +
> +/**
> + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
>   * @frame: HDMI SPD infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> -				size_t size)
> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> +				     void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_spd_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
> +
> +/**
> + * hdmi_spd_infoframe_pack() - Check and check a HDMI SPD infoframe,
> + *                             and write it to binary buffer
> + * @frame: HDMI SPD infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which 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_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
> +				void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_spd_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
>  
>  /**
> @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
>  }
>  EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>  
> +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * hdmi_audio_infoframe_check() - Check and check a HDMI audio infoframe
> + * @frame: HDMI audio infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
> +{
> +	return hdmi_audio_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_audio_infoframe_check);
> +
>  /**
> - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
> + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
>   * @frame: HDMI audio infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> -				  void *buffer, size_t size)
> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> +				       void *buffer, size_t size)
>  {
>  	unsigned char channels;
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_audio_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
> +
> +/**
> + * hdmi_audio_infoframe_pack() - Check and check a HDMI Audio infoframe,
> + *                               and write it to binary buffer
> + * @frame: HDMI Audio infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which 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_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> +				  void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_audio_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
>  
>  /**
> @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
>  	 * value
>  	 */
>  	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
> +	frame->length = 4;
>  
>  	return 0;
>  }
> @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>  		return 4;
>  }
>  
> +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
> +	    frame->version != 1 ||
> +	    frame->oui != HDMI_IEEE_OUI)
> +		return -EINVAL;
> +
> +	/* only one of those can be supplied */
> +	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> +		return -EINVAL;
> +
> +	if (frame->length != hdmi_vendor_infoframe_length(frame))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
> + * hdmi_vendor_infoframe_check() - Check and check a HDMI vendor infoframe
> + * @frame: HDMI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
> +{
> +	frame->length = hdmi_vendor_infoframe_length(frame);
> +
> +	return hdmi_vendor_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
> +
> +/**
> + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
>   * @frame: HDMI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> -				 void *buffer, size_t size)
> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> +					void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
>  
> -	/* only one of those can be supplied */
> -	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> -		return -EINVAL;
> -
> -	frame->length = hdmi_vendor_infoframe_length(frame);
> +	ret = hdmi_vendor_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
> +
> +/**
> + * hdmi_vendor_infoframe_pack() - Check and check a HDMI Vendor infoframe,
> + *                                and write it to binary buffer
> + * @frame: HDMI Vendor infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which 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_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> +				   void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
>  
> +static int
> +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
> +{
> +	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
> +	    frame->any.version != 1)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /*
> - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
> + * hdmi_vendor_any_infoframe_check() - check and check a vendor infoframe
> + */
> +static int
> +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
> +	/* we only know about HDMI vendor infoframes */
> +	if (frame->any.oui != HDMI_IEEE_OUI)
> +		return -EINVAL;
> +
> +	return hdmi_vendor_infoframe_check(&frame->hdmi);
> +}
> +
> +/*
> + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
>   */
>  static ssize_t
> -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> -			   void *buffer, size_t size)
> +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
> +				    void *buffer, size_t size)
>  {
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
>  	/* we only know about HDMI vendor infoframes */
>  	if (frame->any.oui != HDMI_IEEE_OUI)
>  		return -EINVAL;
>  
> -	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
> +	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
> +}
> +
> +/*
> + * hdmi_vendor_any_infoframe_pack() - check and check a vendor infoframe,
> + *                                              and write it to binary buffer
> + */
> +static ssize_t
> +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> +			       void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
> +}
> +
> +/**
> + * hdmi_infoframe_check() - Check check a HDMI infoframe
> + * @frame: HDMI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int
> +hdmi_infoframe_check(union hdmi_infoframe *frame)
> +{
> +	switch (frame->any.type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		return hdmi_avi_infoframe_check(&frame->avi);
> +	case HDMI_INFOFRAME_TYPE_SPD:
> +		return hdmi_spd_infoframe_check(&frame->spd);
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		return hdmi_audio_infoframe_check(&frame->audio);
> +	case HDMI_INFOFRAME_TYPE_VENDOR:
> +		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> +	default:
> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> +		return -EINVAL;
> +	}
>  }
> +EXPORT_SYMBOL(hdmi_infoframe_check);
>  
>  /**
> - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
> + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
>   * @frame: HDMI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>   * error code on failure.
>   */
>  ssize_t
> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
> +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
> +{
> +	ssize_t length;
> +
> +	switch (frame->any.type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		length = hdmi_avi_infoframe_pack_only(&frame->avi,
> +						      buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_SPD:
> +		length = hdmi_spd_infoframe_pack_only(&frame->spd,
> +						      buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		length = hdmi_audio_infoframe_pack_only(&frame->audio,
> +							buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_VENDOR:
> +		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
> +							     buffer, size);
> +		break;
> +	default:
> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> +		length = -EINVAL;
> +	}
> +
> +	return length;
> +}
> +EXPORT_SYMBOL(hdmi_infoframe_pack_only);
> +
> +/**
> + * hdmi_infoframe_pack() - Check check a HDMI infoframe,

Check check?

> + *                         and write it to binary buffer
> + * @frame: HDMI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which 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_infoframe_pack(union hdmi_infoframe *frame,
> +		    void *buffer, size_t size)
>  {
>  	ssize_t length;
>  
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index bce1abb1fe57..c76b50a48e48 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
>  int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
>  ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>  				size_t size);
> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> +				     void *buffer, size_t size);
> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
>  
>  enum hdmi_spd_sdi {
>  	HDMI_SPD_SDI_UNKNOWN,
> @@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>  			    const char *vendor, const char *product);
>  ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>  				size_t size);
> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> +				     void *buffer, size_t size);
> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
>  
>  enum hdmi_audio_coding_type {
>  	HDMI_AUDIO_CODING_TYPE_STREAM,
> @@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
>  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);
> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> +				       void *buffer, size_t size);
> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
>  
>  enum hdmi_3d_structure {
>  	HDMI_3D_STRUCTURE_INVALID = -1,
> @@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
>  int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
>  ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>  				   void *buffer, size_t size);
> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> +					void *buffer, size_t size);
> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
>  
>  union hdmi_vendor_any_infoframe {
>  	struct {
> @@ -330,8 +342,11 @@ union hdmi_infoframe {
>  	struct hdmi_audio_infoframe audio;
>  };
>  
> -ssize_t
> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
> +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> +			    size_t size);
> +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
> +				 void *buffer, size_t size);
> +int hdmi_infoframe_check(union hdmi_infoframe *frame);
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  			  const void *buffer, size_t size);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
> 

Regards,

	Hans

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe
  2018-09-20 18:51 ` [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe Ville Syrjala
@ 2018-09-21  8:28   ` Hans Verkuil
  2018-09-21 13:53     ` Ville Syrjälä
  2018-09-21 15:09   ` [PATCH v2 " Ville Syrjala
  1 sibling, 1 reply; 26+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:28 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Add the code to deal with the MPEG source infoframe.
> 
> Blindly typed from the spec, and totally untested.

I'm not sure this patch should be added at all. The CTA-861-G spec (section 6.7)
says that the implementation of this infoframe is not recommended due to unresolved
issues.

I don't think I've ever seen it either.

It obviously doesn't hurt to have this code, but I prefer to wait until there
are devices that actively set/use this infoframe.

Regards,

	Hans

> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/hdmi.h |  27 ++++++
>  2 files changed, 256 insertions(+)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 9507f668a569..3d24c7746c51 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -706,6 +706,131 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>  	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
>  }
>  
> +/**
> + * hdmi_mpeg_source_infoframe_init() - initialize an HDMI MPEG Source infoframe
> + * @frame: HDMI MPEG Source infoframe
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame)
> +{
> +	memset(frame, 0, sizeof(*frame));
> +
> +	frame->type = HDMI_INFOFRAME_TYPE_MPEG_SOURCE;
> +	frame->version = 1;
> +	frame->length = HDMI_MPEG_SOURCE_INFOFRAME_SIZE;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_init);
> +
> +static int hdmi_mpeg_source_infoframe_check_only(const struct hdmi_mpeg_source_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_MPEG_SOURCE_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * hdmi_mpeg_source_infoframe_check() - Check and check a HDMI MPEG Source infoframe
> + * @frame: HDMI MPEG Source infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame)
> +{
> +	return hdmi_mpeg_source_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_check);
> +
> +/**
> + * hdmi_mpeg_source_infoframe_pack_only() - write HDMI MPEG Source infoframe to binary buffer
> + * @frame: HDMI MPEG Source 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_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
> +					     void *buffer, size_t size)
> +{
> +	u8 *ptr = buffer;
> +	size_t length;
> +	int ret;
> +
> +	ret = hdmi_mpeg_source_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
> +	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 */
> +
> +	/* start infoframe payload */
> +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> +
> +	ptr[0] = frame->mpeg_bit_rate >> 0;
> +	ptr[1] = frame->mpeg_bit_rate >> 8;
> +	ptr[2] = frame->mpeg_bit_rate >> 16;
> +	ptr[3] = frame->mpeg_bit_rate >> 24;
> +	ptr[4] = (frame->field_repeat << 4) | frame->mpeg_frame;
> +
> +	hdmi_infoframe_set_checksum(buffer, length);
> +
> +	return length;
> +}
> +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack_only);
> +
> +/**
> + * hdmi_mpeg_source_infoframe_pack() - Check and check a HDMI MPEG Source infoframe,
> + *                                     and write it to binary buffer
> + * @frame: HDMI MPEG Source infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which 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_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
> +					void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_mpeg_source_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_mpeg_source_infoframe_pack_only(frame, buffer, size);
> +}
> +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
> +
>  /**
>   * hdmi_infoframe_check() - Check check a HDMI infoframe
>   * @frame: HDMI infoframe
> @@ -727,6 +852,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
>  		return hdmi_audio_infoframe_check(&frame->audio);
>  	case HDMI_INFOFRAME_TYPE_VENDOR:
>  		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		return -EINVAL;
> @@ -770,6 +897,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
>  		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
>  							     buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
> +							      buffer, size);
> +		break;
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		length = -EINVAL;
> @@ -816,6 +947,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
>  		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
>  							buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
> +							 buffer, size);
> +		break;
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		length = -EINVAL;
> @@ -838,6 +973,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_MPEG_SOURCE:
> +		return "MPEG Source";
>  	}
>  	return "Reserved";
>  }
> @@ -1349,6 +1486,46 @@ hdmi_vendor_any_infoframe_log(const char *level,
>  	}
>  }
>  
> +static const char *
> +hdmi_mpeg_frame_get_name(enum hdmi_mpeg_frame frame)
> +{
> +	if (frame < 0 || frame > 3)
> +		return "invalid";
> +
> +	switch (frame) {
> +	case HDMI_MPEG_FRAME_UNKNOWN:
> +		return "Unknown";
> +	case HDMI_MPEG_FRAME_I_PICTURE:
> +		return "I Picture";
> +	case HDMI_MPEG_FRAME_B_PICTURE:
> +		return "B Picture";
> +	case HDMI_MPEG_FRAME_P_PICTURE:
> +		return "P Picture";
> +	}
> +	return "Reserved";
> +}
> +
> +/**
> + * hdmi_mpeg_source_infoframe_log() - log info of HDMI MPEG Source infoframe
> + * @level: logging level
> + * @dev: device
> + * @frame: HDMI MPEG Source infoframe
> + */
> +static void hdmi_mpeg_source_infoframe_log(const char *level,
> +					   struct device *dev,
> +					   const struct hdmi_mpeg_source_infoframe *frame)
> +{
> +	hdmi_infoframe_log_header(level, dev,
> +				  (const struct hdmi_any_infoframe *)frame);
> +
> +	hdmi_log("    MPEG bit rate: %d Hz\n",
> +		 frame->mpeg_bit_rate);
> +	hdmi_log("    MPEG frame: %s\n",
> +		 hdmi_mpeg_frame_get_name(frame->mpeg_frame));
> +	hdmi_log("    field repeat: %s\n",
> +		 frame->field_repeat ? "Yes" : "No");
> +}
> +
>  /**
>   * hdmi_infoframe_log() - log info of HDMI infoframe
>   * @level: logging level
> @@ -1372,6 +1549,9 @@ void hdmi_infoframe_log(const char *level,
>  	case HDMI_INFOFRAME_TYPE_VENDOR:
>  		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
> +		break;
>  	}
>  }
>  EXPORT_SYMBOL(hdmi_infoframe_log);
> @@ -1614,6 +1794,52 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>  	return 0;
>  }
>  
> +/**
> + * hdmi_mpeg_source_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
> + * @frame: HDMI MPEG Source infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
> + *
> + * Unpacks the information contained in binary @buffer into a structured
> + * @frame of the HDMI MPEG Source 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_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *frame,
> +					     const void *buffer, size_t size)
> +{
> +	const u8 *ptr = buffer;
> +	int ret;
> +
> +	if (size < HDMI_INFOFRAME_SIZE(MPEG_SOURCE))
> +		return -EINVAL;
> +
> +	if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
> +	    ptr[1] != 1 ||
> +	    ptr[2] != HDMI_MPEG_SOURCE_INFOFRAME_SIZE) {
> +		return -EINVAL;
> +	}
> +
> +	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG_SOURCE)) != 0)
> +		return -EINVAL;
> +
> +	ret = hdmi_mpeg_source_infoframe_init(frame);
> +	if (ret)
> +		return ret;
> +
> +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> +
> +	frame->mpeg_bit_rate =
> +		(ptr[0] << 0) | (ptr[1] << 8) |
> +		(ptr[2] << 16) | (ptr[3] << 24);
> +	frame->mpeg_frame = ptr[4] & 0x3;
> +	frame->field_repeat = ptr[4] & 0x10;
> +
> +	return 0;
> +}
> +
>  /**
>   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
>   * @frame: HDMI infoframe
> @@ -1649,6 +1875,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  	case HDMI_INFOFRAME_TYPE_VENDOR:
>  		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
> +		break;
>  	default:
>  		ret = -EINVAL;
>  		break;
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index 80521d9591a1..2c9322f7538d 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
>  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
>  	HDMI_INFOFRAME_TYPE_SPD = 0x83,
>  	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
> +	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
>  };
>  
>  #define HDMI_IEEE_OUI 0x000c03
> @@ -55,6 +56,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_MPEG_SOURCE_INFOFRAME_SIZE  10
>  
>  #define HDMI_INFOFRAME_SIZE(type)	\
>  	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
> @@ -337,6 +339,29 @@ union hdmi_vendor_any_infoframe {
>  	struct hdmi_vendor_infoframe hdmi;
>  };
>  
> +enum hdmi_mpeg_frame {
> +	HDMI_MPEG_FRAME_UNKNOWN,
> +	HDMI_MPEG_FRAME_I_PICTURE,
> +	HDMI_MPEG_FRAME_B_PICTURE,
> +	HDMI_MPEG_FRAME_P_PICTURE,
> +};
> +
> +struct hdmi_mpeg_source_infoframe {
> +	enum hdmi_infoframe_type type;
> +	unsigned char version;
> +	unsigned char length;
> +	unsigned int mpeg_bit_rate;
> +	enum hdmi_mpeg_frame mpeg_frame;
> +	bool field_repeat;
> +};
> +
> +int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame);
> +ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
> +					void *buffer, size_t size);
> +ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
> +					     void *buffer, size_t size);
> +int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
> +
>  /**
>   * union hdmi_infoframe - overall union of all abstract infoframe representations
>   * @any: generic infoframe
> @@ -344,6 +369,7 @@ union hdmi_vendor_any_infoframe {
>   * @spd: spd infoframe
>   * @vendor: union of all vendor infoframes
>   * @audio: audio infoframe
> + * @mpeg_source: mpeg source infoframe
>   *
>   * This is used by the generic pack function. This works since all infoframes
>   * have the same header which also indicates which type of infoframe should be
> @@ -355,6 +381,7 @@ union hdmi_infoframe {
>  	struct hdmi_spd_infoframe spd;
>  	union hdmi_vendor_any_infoframe vendor;
>  	struct hdmi_audio_infoframe audio;
> +	struct hdmi_mpeg_source_infoframe mpeg_source;
>  };
>  
>  ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe
  2018-09-20 18:51 ` [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe Ville Syrjala
@ 2018-09-21  8:30   ` Hans Verkuil
  2018-09-21 13:54     ` Ville Syrjälä
  2018-09-21 15:10   ` [PATCH v2 " Ville Syrjala
  1 sibling, 1 reply; 26+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:30 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Add the code to deal with the NTSC VBI infoframe.
> 
> I decided against parsing the PES_data_field and just leave
> it as an opaque blob, just dumping it out as hex in the log.
> 
> Blindly typed from the spec, and totally untested.

Do we have any driver that uses this? I would prefer to wait until someone
actually need this.

Regards,

	Hans

> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/hdmi.h |  18 +++++
>  2 files changed, 226 insertions(+)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 3d24c7746c51..3c320d69fa0a 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -831,6 +831,139 @@ ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame
>  }
>  EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
>  
> +/**
> + * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI NTSC VBI infoframe
> + * @frame: HDMI NTSC VBI infoframe
> + * @pes_data_field: ANSI/SCTE 127 PES_data_field
> + * @length: ANSI/SCTE 127 PES_data_field length
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
> +				 const void *pes_data_field,
> +				 size_t length)
> +{
> +	if (length < 1 || length > 27)
> +		return -EINVAL;
> +
> +	memset(frame, 0, sizeof(*frame));
> +
> +	frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
> +	frame->version = 1;
> +	frame->length = length;
> +
> +	memcpy(frame->pes_data_field, pes_data_field, length);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
> +
> +static int hdmi_ntsc_vbi_infoframe_check_only(const struct hdmi_ntsc_vbi_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
> +	    frame->version != 1 ||
> +	    frame->length < 1 || frame->length > 27)
> +		return -EINVAL;
> +
> +	if (frame->pes_data_field[0] != 0x99)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * hdmi_ntsc_vbi_infoframe_check() - Check and check a HDMI NTSC VBI infoframe
> + * @frame: HDMI NTSC VBI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame)
> +{
> +	return hdmi_ntsc_vbi_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_check);
> +
> +/**
> + * hdmi_ntsc_vbi_infoframe_pack_only() - write HDMI NTSC VBI 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_only(const struct hdmi_ntsc_vbi_infoframe *frame,
> +					  void *buffer, size_t size)
> +{
> +	u8 *ptr = buffer;
> +	size_t length;
> +	int ret;
> +
> +	ret = hdmi_ntsc_vbi_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
> +	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 */
> +
> +	/* start infoframe payload */
> +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> +
> +	memcpy(ptr, frame->pes_data_field, frame->length);
> +
> +	hdmi_infoframe_set_checksum(buffer, length);
> +
> +	return length;
> +}
> +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack_only);
> +
> +/**
> + * hdmi_ntsc_vbi_infoframe_pack() - Check and check a HDMI NTSC VBI infoframe,
> + *                                  and write it to binary buffer
> + * @frame: HDMI NTSC VBI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which 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)
> +{
> +	int ret;
> +
> +	ret = hdmi_ntsc_vbi_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_ntsc_vbi_infoframe_pack_only(frame, buffer, size);
> +}
> +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
> +
>  /**
>   * hdmi_infoframe_check() - Check check a HDMI infoframe
>   * @frame: HDMI infoframe
> @@ -854,6 +987,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
>  		return hdmi_vendor_any_infoframe_check(&frame->vendor);
>  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
>  		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		return -EINVAL;
> @@ -901,6 +1036,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
>  		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
>  							      buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		length = hdmi_ntsc_vbi_infoframe_pack_only(&frame->ntsc_vbi,
> +							   buffer, size);
> +		break;
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		length = -EINVAL;
> @@ -951,6 +1090,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
>  		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
>  							 buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi,
> +						      buffer, size);
> +		break;
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		length = -EINVAL;
> @@ -975,6 +1118,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
>  		return "Audio";
>  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
>  		return "MPEG Source";
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		return "NTSC VBI";
>  	}
>  	return "Reserved";
>  }
> @@ -1526,6 +1671,22 @@ static void hdmi_mpeg_source_infoframe_log(const char *level,
>  		 frame->field_repeat ? "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,
> +					const struct hdmi_ntsc_vbi_infoframe *frame)
> +{
> +	hdmi_infoframe_log_header(level, dev,
> +				  (const struct hdmi_any_infoframe *)frame);
> +
> +	hdmi_log("    %*ph\n", frame->length, frame->pes_data_field);
> +}
> +
>  /**
>   * hdmi_infoframe_log() - log info of HDMI infoframe
>   * @level: logging level
> @@ -1552,6 +1713,9 @@ void hdmi_infoframe_log(const char *level,
>  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
>  		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
> +		break;
>  	}
>  }
>  EXPORT_SYMBOL(hdmi_infoframe_log);
> @@ -1840,6 +2004,47 @@ static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *
>  	return 0;
>  }
>  
> +/**
> + * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
> + * @frame: HDMI MPEG Source infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
> + *
> + * Unpacks the information contained in binary @buffer into a structured
> + * @frame of the HDMI MPEG Source 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,
> +					  const void *buffer, size_t size)
> +{
> +	const u8 *ptr = buffer;
> +	size_t length;
> +
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE)
> +		return -EINVAL;
> +
> +	if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
> +	    ptr[1] != 1 ||
> +	    ptr[2] < 1 || ptr[2] > 27)
> +		return -EINVAL;
> +
> +	length = ptr[2];
> +
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
> +		return -EINVAL;
> +
> +	if (hdmi_infoframe_checksum(buffer,
> +				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
> +		return -EINVAL;
> +
> +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> +
> +	return hdmi_ntsc_vbi_infoframe_init(frame, ptr, length);
> +}
> +
>  /**
>   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
>   * @frame: HDMI infoframe
> @@ -1878,6 +2083,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
>  		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer, size);
> +		break;
>  	default:
>  		ret = -EINVAL;
>  		break;
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index 2c9322f7538d..3821516b336c 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -48,6 +48,7 @@ enum hdmi_infoframe_type {
>  	HDMI_INFOFRAME_TYPE_SPD = 0x83,
>  	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
>  	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
> +	HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
>  };
>  
>  #define HDMI_IEEE_OUI 0x000c03
> @@ -362,6 +363,21 @@ ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infof
>  					     void *buffer, size_t size);
>  int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
>  
> +struct hdmi_ntsc_vbi_infoframe {
> +	enum hdmi_infoframe_type type;
> +	unsigned char version;
> +	unsigned char length;
> +	unsigned char pes_data_field[27];
> +};
> +
> +int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
> +				 const void *pes_data_field, size_t length);
> +ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
> +				     void *buffer, size_t size);
> +ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
> +					  void *buffer, size_t size);
> +int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame);
> +
>  /**
>   * union hdmi_infoframe - overall union of all abstract infoframe representations
>   * @any: generic infoframe
> @@ -370,6 +386,7 @@ int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
>   * @vendor: union of all vendor infoframes
>   * @audio: audio infoframe
>   * @mpeg_source: mpeg source infoframe
> + * @ntsc_vbi: ntsc vbi infoframe
>   *
>   * This is used by the generic pack function. This works since all infoframes
>   * have the same header which also indicates which type of infoframe should be
> @@ -382,6 +399,7 @@ union hdmi_infoframe {
>  	union hdmi_vendor_any_infoframe vendor;
>  	struct hdmi_audio_infoframe audio;
>  	struct hdmi_mpeg_source_infoframe mpeg_source;
> +	struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
>  };
>  
>  ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
  2018-09-20 18:51 ` [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types Ville Syrjala
@ 2018-09-21  8:41   ` Hans Verkuil
  2018-09-21 14:01     ` Ville Syrjälä
  0 siblings, 1 reply; 26+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:41 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> We'll be wanting to send more than just infoframes over HDMI. So add an
> enum for other packet types.
> 
> TODO: Maybe just include the infoframe types in the packet type enum
>       and get rid of the infoframe type enum?

I think that's better, IMHO. With a comment that the types starting with
0x81 are defined in CTA-861-G.

It's really the same byte that is being checked, so having two enums is
a bit misleading. The main difference is really which standard defines
the packet types.

Regards,

	Hans

> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  include/linux/hdmi.h | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index c76b50a48e48..80521d9591a1 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -27,6 +27,21 @@
>  #include <linux/types.h>
>  #include <linux/device.h>
>  
> +enum hdmi_packet_type {
> +	HDMI_PACKET_TYPE_NULL = 0x00,
> +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
> +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
> +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
> +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
> +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
> +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
> +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
> +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
> +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
> +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
> +	/* + enum hdmi_infoframe_type */
> +};
> +
>  enum hdmi_infoframe_type {
>  	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
>  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe
  2018-09-21  8:28   ` Hans Verkuil
@ 2018-09-21 13:53     ` Ville Syrjälä
  0 siblings, 0 replies; 26+ messages in thread
From: Ville Syrjälä @ 2018-09-21 13:53 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: dri-devel, intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 10:28:09AM +0200, Hans Verkuil wrote:
> On 09/20/18 20:51, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Add the code to deal with the MPEG source infoframe.
> > 
> > Blindly typed from the spec, and totally untested.
> 
> I'm not sure this patch should be added at all. The CTA-861-G spec (section 6.7)
> says that the implementation of this infoframe is not recommended due to unresolved
> issues.
> 
> I don't think I've ever seen it either.
> 
> It obviously doesn't hurt to have this code, but I prefer to wait until there
> are devices that actively set/use this infoframe.

Sure. I'm totally fine with leaving it out. Just figured I'd send it out
in case anyone has some use for it.

> 
> Regards,
> 
> 	Hans
> 
> > 
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Cc: Hans Verkuil <hans.verkuil@cisco.com>
> > Cc: linux-media@vger.kernel.org
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/video/hdmi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  include/linux/hdmi.h |  27 ++++++
> >  2 files changed, 256 insertions(+)
> > 
> > diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> > index 9507f668a569..3d24c7746c51 100644
> > --- a/drivers/video/hdmi.c
> > +++ b/drivers/video/hdmi.c
> > @@ -706,6 +706,131 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> >  	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
> >  }
> >  
> > +/**
> > + * hdmi_mpeg_source_infoframe_init() - initialize an HDMI MPEG Source infoframe
> > + * @frame: HDMI MPEG Source infoframe
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame)
> > +{
> > +	memset(frame, 0, sizeof(*frame));
> > +
> > +	frame->type = HDMI_INFOFRAME_TYPE_MPEG_SOURCE;
> > +	frame->version = 1;
> > +	frame->length = HDMI_MPEG_SOURCE_INFOFRAME_SIZE;
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_init);
> > +
> > +static int hdmi_mpeg_source_infoframe_check_only(const struct hdmi_mpeg_source_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
> > +	    frame->version != 1 ||
> > +	    frame->length != HDMI_MPEG_SOURCE_INFOFRAME_SIZE)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * hdmi_mpeg_source_infoframe_check() - Check and check a HDMI MPEG Source infoframe
> > + * @frame: HDMI MPEG Source infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame)
> > +{
> > +	return hdmi_mpeg_source_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_check);
> > +
> > +/**
> > + * hdmi_mpeg_source_infoframe_pack_only() - write HDMI MPEG Source infoframe to binary buffer
> > + * @frame: HDMI MPEG Source 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_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
> > +					     void *buffer, size_t size)
> > +{
> > +	u8 *ptr = buffer;
> > +	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_mpeg_source_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	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 */
> > +
> > +	/* start infoframe payload */
> > +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> > +
> > +	ptr[0] = frame->mpeg_bit_rate >> 0;
> > +	ptr[1] = frame->mpeg_bit_rate >> 8;
> > +	ptr[2] = frame->mpeg_bit_rate >> 16;
> > +	ptr[3] = frame->mpeg_bit_rate >> 24;
> > +	ptr[4] = (frame->field_repeat << 4) | frame->mpeg_frame;
> > +
> > +	hdmi_infoframe_set_checksum(buffer, length);
> > +
> > +	return length;
> > +}
> > +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_mpeg_source_infoframe_pack() - Check and check a HDMI MPEG Source infoframe,
> > + *                                     and write it to binary buffer
> > + * @frame: HDMI MPEG Source infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which 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_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
> > +					void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_mpeg_source_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_mpeg_source_infoframe_pack_only(frame, buffer, size);
> > +}
> > +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
> > +
> >  /**
> >   * hdmi_infoframe_check() - Check check a HDMI infoframe
> >   * @frame: HDMI infoframe
> > @@ -727,6 +852,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
> >  		return hdmi_audio_infoframe_check(&frame->audio);
> >  	case HDMI_INFOFRAME_TYPE_VENDOR:
> >  		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		return -EINVAL;
> > @@ -770,6 +897,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
> >  		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
> >  							     buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
> > +							      buffer, size);
> > +		break;
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		length = -EINVAL;
> > @@ -816,6 +947,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
> >  		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
> >  							buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
> > +							 buffer, size);
> > +		break;
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		length = -EINVAL;
> > @@ -838,6 +973,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_MPEG_SOURCE:
> > +		return "MPEG Source";
> >  	}
> >  	return "Reserved";
> >  }
> > @@ -1349,6 +1486,46 @@ hdmi_vendor_any_infoframe_log(const char *level,
> >  	}
> >  }
> >  
> > +static const char *
> > +hdmi_mpeg_frame_get_name(enum hdmi_mpeg_frame frame)
> > +{
> > +	if (frame < 0 || frame > 3)
> > +		return "invalid";
> > +
> > +	switch (frame) {
> > +	case HDMI_MPEG_FRAME_UNKNOWN:
> > +		return "Unknown";
> > +	case HDMI_MPEG_FRAME_I_PICTURE:
> > +		return "I Picture";
> > +	case HDMI_MPEG_FRAME_B_PICTURE:
> > +		return "B Picture";
> > +	case HDMI_MPEG_FRAME_P_PICTURE:
> > +		return "P Picture";
> > +	}
> > +	return "Reserved";
> > +}
> > +
> > +/**
> > + * hdmi_mpeg_source_infoframe_log() - log info of HDMI MPEG Source infoframe
> > + * @level: logging level
> > + * @dev: device
> > + * @frame: HDMI MPEG Source infoframe
> > + */
> > +static void hdmi_mpeg_source_infoframe_log(const char *level,
> > +					   struct device *dev,
> > +					   const struct hdmi_mpeg_source_infoframe *frame)
> > +{
> > +	hdmi_infoframe_log_header(level, dev,
> > +				  (const struct hdmi_any_infoframe *)frame);
> > +
> > +	hdmi_log("    MPEG bit rate: %d Hz\n",
> > +		 frame->mpeg_bit_rate);
> > +	hdmi_log("    MPEG frame: %s\n",
> > +		 hdmi_mpeg_frame_get_name(frame->mpeg_frame));
> > +	hdmi_log("    field repeat: %s\n",
> > +		 frame->field_repeat ? "Yes" : "No");
> > +}
> > +
> >  /**
> >   * hdmi_infoframe_log() - log info of HDMI infoframe
> >   * @level: logging level
> > @@ -1372,6 +1549,9 @@ void hdmi_infoframe_log(const char *level,
> >  	case HDMI_INFOFRAME_TYPE_VENDOR:
> >  		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
> > +		break;
> >  	}
> >  }
> >  EXPORT_SYMBOL(hdmi_infoframe_log);
> > @@ -1614,6 +1794,52 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
> >  	return 0;
> >  }
> >  
> > +/**
> > + * hdmi_mpeg_source_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
> > + * @frame: HDMI MPEG Source infoframe
> > + * @buffer: source buffer
> > + * @size: size of buffer
> > + *
> > + * Unpacks the information contained in binary @buffer into a structured
> > + * @frame of the HDMI MPEG Source 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_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *frame,
> > +					     const void *buffer, size_t size)
> > +{
> > +	const u8 *ptr = buffer;
> > +	int ret;
> > +
> > +	if (size < HDMI_INFOFRAME_SIZE(MPEG_SOURCE))
> > +		return -EINVAL;
> > +
> > +	if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
> > +	    ptr[1] != 1 ||
> > +	    ptr[2] != HDMI_MPEG_SOURCE_INFOFRAME_SIZE) {
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG_SOURCE)) != 0)
> > +		return -EINVAL;
> > +
> > +	ret = hdmi_mpeg_source_infoframe_init(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> > +
> > +	frame->mpeg_bit_rate =
> > +		(ptr[0] << 0) | (ptr[1] << 8) |
> > +		(ptr[2] << 16) | (ptr[3] << 24);
> > +	frame->mpeg_frame = ptr[4] & 0x3;
> > +	frame->field_repeat = ptr[4] & 0x10;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> >   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
> >   * @frame: HDMI infoframe
> > @@ -1649,6 +1875,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> >  	case HDMI_INFOFRAME_TYPE_VENDOR:
> >  		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
> > +		break;
> >  	default:
> >  		ret = -EINVAL;
> >  		break;
> > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> > index 80521d9591a1..2c9322f7538d 100644
> > --- a/include/linux/hdmi.h
> > +++ b/include/linux/hdmi.h
> > @@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
> >  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
> >  	HDMI_INFOFRAME_TYPE_SPD = 0x83,
> >  	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
> > +	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
> >  };
> >  
> >  #define HDMI_IEEE_OUI 0x000c03
> > @@ -55,6 +56,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_MPEG_SOURCE_INFOFRAME_SIZE  10
> >  
> >  #define HDMI_INFOFRAME_SIZE(type)	\
> >  	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
> > @@ -337,6 +339,29 @@ union hdmi_vendor_any_infoframe {
> >  	struct hdmi_vendor_infoframe hdmi;
> >  };
> >  
> > +enum hdmi_mpeg_frame {
> > +	HDMI_MPEG_FRAME_UNKNOWN,
> > +	HDMI_MPEG_FRAME_I_PICTURE,
> > +	HDMI_MPEG_FRAME_B_PICTURE,
> > +	HDMI_MPEG_FRAME_P_PICTURE,
> > +};
> > +
> > +struct hdmi_mpeg_source_infoframe {
> > +	enum hdmi_infoframe_type type;
> > +	unsigned char version;
> > +	unsigned char length;
> > +	unsigned int mpeg_bit_rate;
> > +	enum hdmi_mpeg_frame mpeg_frame;
> > +	bool field_repeat;
> > +};
> > +
> > +int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame);
> > +ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
> > +					void *buffer, size_t size);
> > +ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
> > +					     void *buffer, size_t size);
> > +int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
> > +
> >  /**
> >   * union hdmi_infoframe - overall union of all abstract infoframe representations
> >   * @any: generic infoframe
> > @@ -344,6 +369,7 @@ union hdmi_vendor_any_infoframe {
> >   * @spd: spd infoframe
> >   * @vendor: union of all vendor infoframes
> >   * @audio: audio infoframe
> > + * @mpeg_source: mpeg source infoframe
> >   *
> >   * This is used by the generic pack function. This works since all infoframes
> >   * have the same header which also indicates which type of infoframe should be
> > @@ -355,6 +381,7 @@ union hdmi_infoframe {
> >  	struct hdmi_spd_infoframe spd;
> >  	union hdmi_vendor_any_infoframe vendor;
> >  	struct hdmi_audio_infoframe audio;
> > +	struct hdmi_mpeg_source_infoframe mpeg_source;
> >  };
> >  
> >  ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> > 

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe
  2018-09-21  8:30   ` Hans Verkuil
@ 2018-09-21 13:54     ` Ville Syrjälä
  0 siblings, 0 replies; 26+ messages in thread
From: Ville Syrjälä @ 2018-09-21 13:54 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: dri-devel, intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 10:30:16AM +0200, Hans Verkuil wrote:
> On 09/20/18 20:51, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Add the code to deal with the NTSC VBI infoframe.
> > 
> > I decided against parsing the PES_data_field and just leave
> > it as an opaque blob, just dumping it out as hex in the log.
> > 
> > Blindly typed from the spec, and totally untested.
> 
> Do we have any driver that uses this? I would prefer to wait until someone
> actually need this.

No users that I know of. So totally fine with me to leave it out.

> 
> Regards,
> 
> 	Hans
> 
> > 
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Cc: Hans Verkuil <hans.verkuil@cisco.com>
> > Cc: linux-media@vger.kernel.org
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/video/hdmi.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  include/linux/hdmi.h |  18 +++++
> >  2 files changed, 226 insertions(+)
> > 
> > diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> > index 3d24c7746c51..3c320d69fa0a 100644
> > --- a/drivers/video/hdmi.c
> > +++ b/drivers/video/hdmi.c
> > @@ -831,6 +831,139 @@ ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame
> >  }
> >  EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
> >  
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI NTSC VBI infoframe
> > + * @frame: HDMI NTSC VBI infoframe
> > + * @pes_data_field: ANSI/SCTE 127 PES_data_field
> > + * @length: ANSI/SCTE 127 PES_data_field length
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
> > +				 const void *pes_data_field,
> > +				 size_t length)
> > +{
> > +	if (length < 1 || length > 27)
> > +		return -EINVAL;
> > +
> > +	memset(frame, 0, sizeof(*frame));
> > +
> > +	frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
> > +	frame->version = 1;
> > +	frame->length = length;
> > +
> > +	memcpy(frame->pes_data_field, pes_data_field, length);
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
> > +
> > +static int hdmi_ntsc_vbi_infoframe_check_only(const struct hdmi_ntsc_vbi_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
> > +	    frame->version != 1 ||
> > +	    frame->length < 1 || frame->length > 27)
> > +		return -EINVAL;
> > +
> > +	if (frame->pes_data_field[0] != 0x99)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_check() - Check and check a HDMI NTSC VBI infoframe
> > + * @frame: HDMI NTSC VBI infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame)
> > +{
> > +	return hdmi_ntsc_vbi_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_check);
> > +
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_pack_only() - write HDMI NTSC VBI 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_only(const struct hdmi_ntsc_vbi_infoframe *frame,
> > +					  void *buffer, size_t size)
> > +{
> > +	u8 *ptr = buffer;
> > +	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_ntsc_vbi_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	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 */
> > +
> > +	/* start infoframe payload */
> > +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> > +
> > +	memcpy(ptr, frame->pes_data_field, frame->length);
> > +
> > +	hdmi_infoframe_set_checksum(buffer, length);
> > +
> > +	return length;
> > +}
> > +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_pack() - Check and check a HDMI NTSC VBI infoframe,
> > + *                                  and write it to binary buffer
> > + * @frame: HDMI NTSC VBI infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which 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)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_ntsc_vbi_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_ntsc_vbi_infoframe_pack_only(frame, buffer, size);
> > +}
> > +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
> > +
> >  /**
> >   * hdmi_infoframe_check() - Check check a HDMI infoframe
> >   * @frame: HDMI infoframe
> > @@ -854,6 +987,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
> >  		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> >  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> >  		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		return -EINVAL;
> > @@ -901,6 +1036,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
> >  		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
> >  							      buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		length = hdmi_ntsc_vbi_infoframe_pack_only(&frame->ntsc_vbi,
> > +							   buffer, size);
> > +		break;
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		length = -EINVAL;
> > @@ -951,6 +1090,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
> >  		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
> >  							 buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi,
> > +						      buffer, size);
> > +		break;
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		length = -EINVAL;
> > @@ -975,6 +1118,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
> >  		return "Audio";
> >  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> >  		return "MPEG Source";
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		return "NTSC VBI";
> >  	}
> >  	return "Reserved";
> >  }
> > @@ -1526,6 +1671,22 @@ static void hdmi_mpeg_source_infoframe_log(const char *level,
> >  		 frame->field_repeat ? "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,
> > +					const struct hdmi_ntsc_vbi_infoframe *frame)
> > +{
> > +	hdmi_infoframe_log_header(level, dev,
> > +				  (const struct hdmi_any_infoframe *)frame);
> > +
> > +	hdmi_log("    %*ph\n", frame->length, frame->pes_data_field);
> > +}
> > +
> >  /**
> >   * hdmi_infoframe_log() - log info of HDMI infoframe
> >   * @level: logging level
> > @@ -1552,6 +1713,9 @@ void hdmi_infoframe_log(const char *level,
> >  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> >  		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
> > +		break;
> >  	}
> >  }
> >  EXPORT_SYMBOL(hdmi_infoframe_log);
> > @@ -1840,6 +2004,47 @@ static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *
> >  	return 0;
> >  }
> >  
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
> > + * @frame: HDMI MPEG Source infoframe
> > + * @buffer: source buffer
> > + * @size: size of buffer
> > + *
> > + * Unpacks the information contained in binary @buffer into a structured
> > + * @frame of the HDMI MPEG Source 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,
> > +					  const void *buffer, size_t size)
> > +{
> > +	const u8 *ptr = buffer;
> > +	size_t length;
> > +
> > +	if (size < HDMI_INFOFRAME_HEADER_SIZE)
> > +		return -EINVAL;
> > +
> > +	if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
> > +	    ptr[1] != 1 ||
> > +	    ptr[2] < 1 || ptr[2] > 27)
> > +		return -EINVAL;
> > +
> > +	length = ptr[2];
> > +
> > +	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
> > +		return -EINVAL;
> > +
> > +	if (hdmi_infoframe_checksum(buffer,
> > +				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
> > +		return -EINVAL;
> > +
> > +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> > +
> > +	return hdmi_ntsc_vbi_infoframe_init(frame, ptr, length);
> > +}
> > +
> >  /**
> >   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
> >   * @frame: HDMI infoframe
> > @@ -1878,6 +2083,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> >  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> >  		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer, size);
> > +		break;
> >  	default:
> >  		ret = -EINVAL;
> >  		break;
> > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> > index 2c9322f7538d..3821516b336c 100644
> > --- a/include/linux/hdmi.h
> > +++ b/include/linux/hdmi.h
> > @@ -48,6 +48,7 @@ enum hdmi_infoframe_type {
> >  	HDMI_INFOFRAME_TYPE_SPD = 0x83,
> >  	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
> >  	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
> > +	HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
> >  };
> >  
> >  #define HDMI_IEEE_OUI 0x000c03
> > @@ -362,6 +363,21 @@ ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infof
> >  					     void *buffer, size_t size);
> >  int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
> >  
> > +struct hdmi_ntsc_vbi_infoframe {
> > +	enum hdmi_infoframe_type type;
> > +	unsigned char version;
> > +	unsigned char length;
> > +	unsigned char pes_data_field[27];
> > +};
> > +
> > +int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
> > +				 const void *pes_data_field, size_t length);
> > +ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
> > +				     void *buffer, size_t size);
> > +ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
> > +					  void *buffer, size_t size);
> > +int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame);
> > +
> >  /**
> >   * union hdmi_infoframe - overall union of all abstract infoframe representations
> >   * @any: generic infoframe
> > @@ -370,6 +386,7 @@ int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
> >   * @vendor: union of all vendor infoframes
> >   * @audio: audio infoframe
> >   * @mpeg_source: mpeg source infoframe
> > + * @ntsc_vbi: ntsc vbi infoframe
> >   *
> >   * This is used by the generic pack function. This works since all infoframes
> >   * have the same header which also indicates which type of infoframe should be
> > @@ -382,6 +399,7 @@ union hdmi_infoframe {
> >  	union hdmi_vendor_any_infoframe vendor;
> >  	struct hdmi_audio_infoframe audio;
> >  	struct hdmi_mpeg_source_infoframe mpeg_source;
> > +	struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
> >  };
> >  
> >  ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> > 

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
  2018-09-21  8:41   ` Hans Verkuil
@ 2018-09-21 14:01     ` Ville Syrjälä
  2018-09-21 14:12       ` Hans Verkuil
  0 siblings, 1 reply; 26+ messages in thread
From: Ville Syrjälä @ 2018-09-21 14:01 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: dri-devel, intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 10:41:46AM +0200, Hans Verkuil wrote:
> On 09/20/18 20:51, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > We'll be wanting to send more than just infoframes over HDMI. So add an
> > enum for other packet types.
> > 
> > TODO: Maybe just include the infoframe types in the packet type enum
> >       and get rid of the infoframe type enum?
> 
> I think that's better, IMHO. With a comment that the types starting with
> 0x81 are defined in CTA-861-G.
> 
> It's really the same byte that is being checked, so having two enums is
> a bit misleading. The main difference is really which standard defines
> the packet types.

Right. The only slight annoyance is that we'll get a bunch of warnings
from the compiler if we don't handle all the enum valus in the switch
statements. If we want to avoid that I guess I could limit this
to just the null, gcp and gamut metadata packets initially and try to
write some actual code for them. Those three are the only ones we
care about in i915 at the moment.

> 
> Regards,
> 
> 	Hans
> 
> > 
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Cc: Hans Verkuil <hans.verkuil@cisco.com>
> > Cc: linux-media@vger.kernel.org
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  include/linux/hdmi.h | 15 +++++++++++++++
> >  1 file changed, 15 insertions(+)
> > 
> > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> > index c76b50a48e48..80521d9591a1 100644
> > --- a/include/linux/hdmi.h
> > +++ b/include/linux/hdmi.h
> > @@ -27,6 +27,21 @@
> >  #include <linux/types.h>
> >  #include <linux/device.h>
> >  
> > +enum hdmi_packet_type {
> > +	HDMI_PACKET_TYPE_NULL = 0x00,
> > +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
> > +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
> > +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
> > +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
> > +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
> > +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
> > +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
> > +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
> > +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
> > +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
> > +	/* + enum hdmi_infoframe_type */
> > +};
> > +
> >  enum hdmi_infoframe_type {
> >  	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
> >  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
> > 

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
  2018-09-21 14:01     ` Ville Syrjälä
@ 2018-09-21 14:12       ` Hans Verkuil
  2018-09-21 15:07         ` Ville Syrjälä
  0 siblings, 1 reply; 26+ messages in thread
From: Hans Verkuil @ 2018-09-21 14:12 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: dri-devel, intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/21/18 16:01, Ville Syrjälä wrote:
> On Fri, Sep 21, 2018 at 10:41:46AM +0200, Hans Verkuil wrote:
>> On 09/20/18 20:51, Ville Syrjala wrote:
>>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>>
>>> We'll be wanting to send more than just infoframes over HDMI. So add an
>>> enum for other packet types.
>>>
>>> TODO: Maybe just include the infoframe types in the packet type enum
>>>       and get rid of the infoframe type enum?
>>
>> I think that's better, IMHO. With a comment that the types starting with
>> 0x81 are defined in CTA-861-G.
>>
>> It's really the same byte that is being checked, so having two enums is
>> a bit misleading. The main difference is really which standard defines
>> the packet types.
> 
> Right. The only slight annoyance is that we'll get a bunch of warnings
> from the compiler if we don't handle all the enum valus in the switch
> statements. If we want to avoid that I guess I could limit this
> to just the null, gcp and gamut metadata packets initially and try to
> write some actual code for them. Those three are the only ones we
> care about in i915 at the moment.

Note that I don't have a terribly strong opinion on this, so if using
one enum instead of two causes more problems than it is worth, then
that's fine with me as well.

But you asked, and given a choice with all other things being equal,
then one enum has my preference.

Regards,

	Hans

> 
>>
>> Regards,
>>
>> 	Hans
>>
>>>
>>> Cc: Thierry Reding <thierry.reding@gmail.com>
>>> Cc: Hans Verkuil <hans.verkuil@cisco.com>
>>> Cc: linux-media@vger.kernel.org
>>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>> ---
>>>  include/linux/hdmi.h | 15 +++++++++++++++
>>>  1 file changed, 15 insertions(+)
>>>
>>> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
>>> index c76b50a48e48..80521d9591a1 100644
>>> --- a/include/linux/hdmi.h
>>> +++ b/include/linux/hdmi.h
>>> @@ -27,6 +27,21 @@
>>>  #include <linux/types.h>
>>>  #include <linux/device.h>
>>>  
>>> +enum hdmi_packet_type {
>>> +	HDMI_PACKET_TYPE_NULL = 0x00,
>>> +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
>>> +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
>>> +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
>>> +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
>>> +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
>>> +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
>>> +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
>>> +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
>>> +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
>>> +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
>>> +	/* + enum hdmi_infoframe_type */
>>> +};
>>> +
>>>  enum hdmi_infoframe_type {
>>>  	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
>>>  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
>>>
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions
  2018-09-21  8:24   ` Hans Verkuil
@ 2018-09-21 14:30     ` Ville Syrjälä
  0 siblings, 0 replies; 26+ messages in thread
From: Ville Syrjälä @ 2018-09-21 14:30 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: dri-devel, intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 10:24:25AM +0200, Hans Verkuil wrote:
> On 09/20/18 20:51, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Let's make the infoframe pack functions usable with a const infoframe
> > structure. This allows us to precompute the infoframe earlier, and still
> > pack it later when we're no longer allowed to modify the structure.
> > So now we end up with a _check()+_pack_only() or _pack() functions
> > depending on whether you want to precompute the infoframes or not.
> > The names aren't greate but I was lazy and didn't want to change all the
> 
> greate -> great

Thanks for reading through it. Fixed up all the crap you spotted.

> 
> > drivers.
> > 
> > v2: Deal with exynos churn
> >     Actually export the new funcs
> > 
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Cc: Hans Verkuil <hans.verkuil@cisco.com>
> > Cc: linux-media@vger.kernel.org
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
> >  include/linux/hdmi.h |  19 ++-
> >  2 files changed, 416 insertions(+), 28 deletions(-)
> > 
> > diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> > index 53e7ee2c83fc..9507f668a569 100644
> > --- a/drivers/video/hdmi.c
> > +++ b/drivers/video/hdmi.c
> > @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
> >  }
> >  EXPORT_SYMBOL(hdmi_avi_infoframe_init);
> >  
> > +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
> > +	    frame->version != 2 ||
> > +	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
> > +		return -EINVAL;
> > +
> > +	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> > - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
> > + * hdmi_avi_infoframe_check() - Check and check a HDMI AVI infoframe
> 
> "Check and check"? This is repeated elsewhere as well (clearly copy-and-paste).
> 
> > + * @frame: HDMI AVI infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
> > +{
> > +	return hdmi_avi_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_avi_infoframe_check);
> > +
> > +/**
> > + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
> >   * @frame: HDMI AVI infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
> >   * Returns the number of bytes packed into the binary buffer or a negative
> >   * error code on failure.
> >   */
> > -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> > -				size_t size)
> > +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> > +				     void *buffer, size_t size)
> >  {
> >  	u8 *ptr = buffer;
> >  	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_avi_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> >  
> >  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> >  
> >  	if (size < length)
> >  		return -ENOSPC;
> >  
> > -	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> > -		return -EINVAL;
> > -
> >  	memset(buffer, 0, size);
> >  
> >  	ptr[0] = frame->type;
> > @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> >  
> >  	return length;
> >  }
> > +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_avi_infoframe_pack() - Check and check a HDMI AVI infoframe,
> > + *                             and write it to binary buffer
> > + * @frame: HDMI AVI infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> 
> which packs -> which it packs
> 
> Ditto elsewhere.
> 
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> 
> Also -> This function also
> 
> Ditto elsewhere.
> 
> > + * 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_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
> > +				void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_avi_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
> > +}
> >  EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
> >  
> >  /**
> > @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
> >  }
> >  EXPORT_SYMBOL(hdmi_spd_infoframe_init);
> >  
> > +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
> > +	    frame->version != 1 ||
> > +	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> > - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
> > + * hdmi_spd_infoframe_check() - Check and check a HDMI SPD infoframe
> > + * @frame: HDMI SPD infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
> > +{
> > +	return hdmi_spd_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_spd_infoframe_check);
> > +
> > +/**
> > + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
> >   * @frame: HDMI SPD infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
> >   * Returns the number of bytes packed into the binary buffer or a negative
> >   * error code on failure.
> >   */
> > -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> > -				size_t size)
> > +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> > +				     void *buffer, size_t size)
> >  {
> >  	u8 *ptr = buffer;
> >  	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_spd_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> >  
> >  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> >  
> > @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> >  
> >  	return length;
> >  }
> > +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_spd_infoframe_pack() - Check and check a HDMI SPD infoframe,
> > + *                             and write it to binary buffer
> > + * @frame: HDMI SPD infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which 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_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
> > +				void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_spd_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
> > +}
> >  EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
> >  
> >  /**
> > @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
> >  }
> >  EXPORT_SYMBOL(hdmi_audio_infoframe_init);
> >  
> > +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
> > +	    frame->version != 1 ||
> > +	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * hdmi_audio_infoframe_check() - Check and check a HDMI audio infoframe
> > + * @frame: HDMI audio infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
> > +{
> > +	return hdmi_audio_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_audio_infoframe_check);
> > +
> >  /**
> > - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
> > + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
> >   * @frame: HDMI audio infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
> >   * Returns the number of bytes packed into the binary buffer or a negative
> >   * error code on failure.
> >   */
> > -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> > -				  void *buffer, size_t size)
> > +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> > +				       void *buffer, size_t size)
> >  {
> >  	unsigned char channels;
> >  	u8 *ptr = buffer;
> >  	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_audio_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> >  
> >  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> >  
> > @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> >  
> >  	return length;
> >  }
> > +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_audio_infoframe_pack() - Check and check a HDMI Audio infoframe,
> > + *                               and write it to binary buffer
> > + * @frame: HDMI Audio infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which 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_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> > +				  void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_audio_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
> > +}
> >  EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
> >  
> >  /**
> > @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
> >  	 * value
> >  	 */
> >  	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
> > +	frame->length = 4;
> >  
> >  	return 0;
> >  }
> > @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
> >  		return 4;
> >  }
> >  
> > +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
> > +	    frame->version != 1 ||
> > +	    frame->oui != HDMI_IEEE_OUI)
> > +		return -EINVAL;
> > +
> > +	/* only one of those can be supplied */
> > +	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> > +		return -EINVAL;
> > +
> > +	if (frame->length != hdmi_vendor_infoframe_length(frame))
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> > - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
> > + * hdmi_vendor_infoframe_check() - Check and check a HDMI vendor infoframe
> > + * @frame: HDMI infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
> > +{
> > +	frame->length = hdmi_vendor_infoframe_length(frame);
> > +
> > +	return hdmi_vendor_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
> > +
> > +/**
> > + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
> >   * @frame: HDMI infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
> >   * Returns the number of bytes packed into the binary buffer or a negative
> >   * error code on failure.
> >   */
> > -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> > -				 void *buffer, size_t size)
> > +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> > +					void *buffer, size_t size)
> >  {
> >  	u8 *ptr = buffer;
> >  	size_t length;
> > +	int ret;
> >  
> > -	/* only one of those can be supplied */
> > -	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> > -		return -EINVAL;
> > -
> > -	frame->length = hdmi_vendor_infoframe_length(frame);
> > +	ret = hdmi_vendor_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> >  
> >  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> >  
> > @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> >  
> >  	return length;
> >  }
> > +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_vendor_infoframe_pack() - Check and check a HDMI Vendor infoframe,
> > + *                                and write it to binary buffer
> > + * @frame: HDMI Vendor infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which 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_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> > +				   void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_vendor_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
> > +}
> >  EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
> >  
> > +static int
> > +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
> > +{
> > +	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
> > +	    frame->any.version != 1)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> >  /*
> > - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
> > + * hdmi_vendor_any_infoframe_check() - check and check a vendor infoframe
> > + */
> > +static int
> > +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* we only know about HDMI vendor infoframes */
> > +	if (frame->any.oui != HDMI_IEEE_OUI)
> > +		return -EINVAL;
> > +
> > +	return hdmi_vendor_infoframe_check(&frame->hdmi);
> > +}
> > +
> > +/*
> > + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
> >   */
> >  static ssize_t
> > -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> > -			   void *buffer, size_t size)
> > +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
> > +				    void *buffer, size_t size)
> >  {
> > +	int ret;
> > +
> > +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> > +
> >  	/* we only know about HDMI vendor infoframes */
> >  	if (frame->any.oui != HDMI_IEEE_OUI)
> >  		return -EINVAL;
> >  
> > -	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
> > +	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
> > +}
> > +
> > +/*
> > + * hdmi_vendor_any_infoframe_pack() - check and check a vendor infoframe,
> > + *                                              and write it to binary buffer
> > + */
> > +static ssize_t
> > +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> > +			       void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_vendor_any_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
> > +}
> > +
> > +/**
> > + * hdmi_infoframe_check() - Check check a HDMI infoframe
> > + * @frame: HDMI infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int
> > +hdmi_infoframe_check(union hdmi_infoframe *frame)
> > +{
> > +	switch (frame->any.type) {
> > +	case HDMI_INFOFRAME_TYPE_AVI:
> > +		return hdmi_avi_infoframe_check(&frame->avi);
> > +	case HDMI_INFOFRAME_TYPE_SPD:
> > +		return hdmi_spd_infoframe_check(&frame->spd);
> > +	case HDMI_INFOFRAME_TYPE_AUDIO:
> > +		return hdmi_audio_infoframe_check(&frame->audio);
> > +	case HDMI_INFOFRAME_TYPE_VENDOR:
> > +		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> > +	default:
> > +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> > +		return -EINVAL;
> > +	}
> >  }
> > +EXPORT_SYMBOL(hdmi_infoframe_check);
> >  
> >  /**
> > - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
> > + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
> >   * @frame: HDMI infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> >   * error code on failure.
> >   */
> >  ssize_t
> > -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
> > +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
> > +{
> > +	ssize_t length;
> > +
> > +	switch (frame->any.type) {
> > +	case HDMI_INFOFRAME_TYPE_AVI:
> > +		length = hdmi_avi_infoframe_pack_only(&frame->avi,
> > +						      buffer, size);
> > +		break;
> > +	case HDMI_INFOFRAME_TYPE_SPD:
> > +		length = hdmi_spd_infoframe_pack_only(&frame->spd,
> > +						      buffer, size);
> > +		break;
> > +	case HDMI_INFOFRAME_TYPE_AUDIO:
> > +		length = hdmi_audio_infoframe_pack_only(&frame->audio,
> > +							buffer, size);
> > +		break;
> > +	case HDMI_INFOFRAME_TYPE_VENDOR:
> > +		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
> > +							     buffer, size);
> > +		break;
> > +	default:
> > +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> > +		length = -EINVAL;
> > +	}
> > +
> > +	return length;
> > +}
> > +EXPORT_SYMBOL(hdmi_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_infoframe_pack() - Check check a HDMI infoframe,
> 
> Check check?
> 
> > + *                         and write it to binary buffer
> > + * @frame: HDMI infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which 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_infoframe_pack(union hdmi_infoframe *frame,
> > +		    void *buffer, size_t size)
> >  {
> >  	ssize_t length;
> >  
> > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> > index bce1abb1fe57..c76b50a48e48 100644
> > --- a/include/linux/hdmi.h
> > +++ b/include/linux/hdmi.h
> > @@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
> >  int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
> >  ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> >  				size_t size);
> > +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> > +				     void *buffer, size_t size);
> > +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
> >  
> >  enum hdmi_spd_sdi {
> >  	HDMI_SPD_SDI_UNKNOWN,
> > @@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
> >  			    const char *vendor, const char *product);
> >  ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> >  				size_t size);
> > +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> > +				     void *buffer, size_t size);
> > +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
> >  
> >  enum hdmi_audio_coding_type {
> >  	HDMI_AUDIO_CODING_TYPE_STREAM,
> > @@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
> >  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);
> > +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> > +				       void *buffer, size_t size);
> > +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
> >  
> >  enum hdmi_3d_structure {
> >  	HDMI_3D_STRUCTURE_INVALID = -1,
> > @@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
> >  int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
> >  ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> >  				   void *buffer, size_t size);
> > +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> > +					void *buffer, size_t size);
> > +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
> >  
> >  union hdmi_vendor_any_infoframe {
> >  	struct {
> > @@ -330,8 +342,11 @@ union hdmi_infoframe {
> >  	struct hdmi_audio_infoframe audio;
> >  };
> >  
> > -ssize_t
> > -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
> > +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> > +			    size_t size);
> > +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
> > +				 void *buffer, size_t size);
> > +int hdmi_infoframe_check(union hdmi_infoframe *frame);
> >  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> >  			  const void *buffer, size_t size);
> >  void hdmi_infoframe_log(const char *level, struct device *dev,
> > 
> 
> Regards,
> 
> 	Hans

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v3 04/18] video/hdmi: Constify infoframe passed to the pack functions
  2018-09-20 18:51 ` [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions Ville Syrjala
  2018-09-21  8:24   ` Hans Verkuil
@ 2018-09-21 14:33   ` Ville Syrjala
  2018-10-01 19:10     ` Ville Syrjälä
  1 sibling, 1 reply; 26+ messages in thread
From: Ville Syrjala @ 2018-09-21 14:33 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Let's make the infoframe pack functions usable with a const infoframe
structure. This allows us to precompute the infoframe earlier, and still
pack it later when we're no longer allowed to modify the structure.
So now we end up with a _check()+_pack_only() or _pack() functions
depending on whether you want to precompute the infoframes or not.
The names aren't great but I was lazy and didn't want to change all the
drivers.

v2: Deal with exynos churn
    Actually export the new funcs
v3: Fix various documentation fails (Hans)

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
 include/linux/hdmi.h |  19 ++-
 2 files changed, 416 insertions(+), 28 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 53e7ee2c83fc..08d94ab00467 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_avi_infoframe_init);
 
+static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
+	    frame->version != 2 ||
+	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
+ * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
+ * @frame: HDMI AVI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
+{
+	return hdmi_avi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_avi_infoframe_check);
+
+/**
+ * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
  * @frame: HDMI AVI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
-				size_t size)
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+				     void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_avi_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
 	if (size < length)
 		return -ENOSPC;
 
-	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
-		return -EINVAL;
-
 	memset(buffer, 0, size);
 
 	ptr[0] = frame->type;
@@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
+
+/**
+ * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI AVI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * 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_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
+				void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_avi_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
 
 /**
@@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 }
 EXPORT_SYMBOL(hdmi_spd_infoframe_init);
 
+static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
+ * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
+ * @frame: HDMI SPD infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
+{
+	return hdmi_spd_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_spd_infoframe_check);
+
+/**
+ * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
  * @frame: HDMI SPD infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
-				size_t size)
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+				     void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_spd_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
+
+/**
+ * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI SPD infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * 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_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
+				void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_spd_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
 
 /**
@@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_audio_infoframe_init);
 
+static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
+ * @frame: HDMI audio infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
+{
+	return hdmi_audio_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_check);
+
 /**
- * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
+ * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
  * @frame: HDMI audio infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
-				  void *buffer, size_t size)
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+				       void *buffer, size_t size)
 {
 	unsigned char channels;
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_audio_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
+
+/**
+ * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
+ *                               and write it to binary buffer
+ * @frame: HDMI Audio infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * 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_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
+				  void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_audio_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
 
 /**
@@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
 	 * value
 	 */
 	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
+	frame->length = 4;
 
 	return 0;
 }
@@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
 		return 4;
 }
 
+static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->version != 1 ||
+	    frame->oui != HDMI_IEEE_OUI)
+		return -EINVAL;
+
+	/* only one of those can be supplied */
+	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+		return -EINVAL;
+
+	if (frame->length != hdmi_vendor_infoframe_length(frame))
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
+ * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
+{
+	frame->length = hdmi_vendor_infoframe_length(frame);
+
+	return hdmi_vendor_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
+
+/**
+ * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
-				 void *buffer, size_t size)
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+					void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
 
-	/* only one of those can be supplied */
-	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
-		return -EINVAL;
-
-	frame->length = hdmi_vendor_infoframe_length(frame);
+	ret = hdmi_vendor_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
+
+/**
+ * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
+ *                                and write it to binary buffer
+ * @frame: HDMI Vendor infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * 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_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
+				   void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_vendor_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
 
+static int
+hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
+{
+	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->any.version != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
 /*
- * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
+ * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
+ */
+static int
+hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
+{
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	/* we only know about HDMI vendor infoframes */
+	if (frame->any.oui != HDMI_IEEE_OUI)
+		return -EINVAL;
+
+	return hdmi_vendor_infoframe_check(&frame->hdmi);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
  */
 static ssize_t
-hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
-			   void *buffer, size_t size)
+hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
+				    void *buffer, size_t size)
 {
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
 	/* we only know about HDMI vendor infoframes */
 	if (frame->any.oui != HDMI_IEEE_OUI)
 		return -EINVAL;
 
-	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
+	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
+ *                                    and write it to binary buffer
+ */
+static ssize_t
+hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
+			       void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
+}
+
+/**
+ * hdmi_infoframe_check() - check a HDMI infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int
+hdmi_infoframe_check(union hdmi_infoframe *frame)
+{
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		return hdmi_avi_infoframe_check(&frame->avi);
+	case HDMI_INFOFRAME_TYPE_SPD:
+		return hdmi_spd_infoframe_check(&frame->spd);
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		return hdmi_audio_infoframe_check(&frame->audio);
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		return hdmi_vendor_any_infoframe_check(&frame->vendor);
+	default:
+		WARN(1, "Bad infoframe type %d\n", frame->any.type);
+		return -EINVAL;
+	}
 }
+EXPORT_SYMBOL(hdmi_infoframe_check);
 
 /**
- * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
+ * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
  * error code on failure.
  */
 ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
+hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
+{
+	ssize_t length;
+
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		length = hdmi_avi_infoframe_pack_only(&frame->avi,
+						      buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_SPD:
+		length = hdmi_spd_infoframe_pack_only(&frame->spd,
+						      buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		length = hdmi_audio_infoframe_pack_only(&frame->audio,
+							buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
+							     buffer, size);
+		break;
+	default:
+		WARN(1, "Bad infoframe type %d\n", frame->any.type);
+		length = -EINVAL;
+	}
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_infoframe_pack_only);
+
+/**
+ * hdmi_infoframe_pack() - check a HDMI infoframe,
+ *                         and write it to binary buffer
+ * @frame: HDMI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * 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_infoframe_pack(union hdmi_infoframe *frame,
+		    void *buffer, size_t size)
 {
 	ssize_t length;
 
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index bce1abb1fe57..c76b50a48e48 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
 int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
 ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
 				size_t size);
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+				     void *buffer, size_t size);
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
 
 enum hdmi_spd_sdi {
 	HDMI_SPD_SDI_UNKNOWN,
@@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 			    const char *vendor, const char *product);
 ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 				size_t size);
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+				     void *buffer, size_t size);
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
 
 enum hdmi_audio_coding_type {
 	HDMI_AUDIO_CODING_TYPE_STREAM,
@@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
 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);
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+				       void *buffer, size_t size);
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
 
 enum hdmi_3d_structure {
 	HDMI_3D_STRUCTURE_INVALID = -1,
@@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
 int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
 ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 				   void *buffer, size_t size);
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+					void *buffer, size_t size);
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
 
 union hdmi_vendor_any_infoframe {
 	struct {
@@ -330,8 +342,11 @@ union hdmi_infoframe {
 	struct hdmi_audio_infoframe audio;
 };
 
-ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
+ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
+			    size_t size);
+ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
+				 void *buffer, size_t size);
+int hdmi_infoframe_check(union hdmi_infoframe *frame);
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 			  const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
  2018-09-21 14:12       ` Hans Verkuil
@ 2018-09-21 15:07         ` Ville Syrjälä
  0 siblings, 0 replies; 26+ messages in thread
From: Ville Syrjälä @ 2018-09-21 15:07 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: dri-devel, intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 04:12:36PM +0200, Hans Verkuil wrote:
> On 09/21/18 16:01, Ville Syrjälä wrote:
> > On Fri, Sep 21, 2018 at 10:41:46AM +0200, Hans Verkuil wrote:
> >> On 09/20/18 20:51, Ville Syrjala wrote:
> >>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>>
> >>> We'll be wanting to send more than just infoframes over HDMI. So add an
> >>> enum for other packet types.
> >>>
> >>> TODO: Maybe just include the infoframe types in the packet type enum
> >>>       and get rid of the infoframe type enum?
> >>
> >> I think that's better, IMHO. With a comment that the types starting with
> >> 0x81 are defined in CTA-861-G.
> >>
> >> It's really the same byte that is being checked, so having two enums is
> >> a bit misleading. The main difference is really which standard defines
> >> the packet types.
> > 
> > Right. The only slight annoyance is that we'll get a bunch of warnings
> > from the compiler if we don't handle all the enum valus in the switch
> > statements. If we want to avoid that I guess I could limit this
> > to just the null, gcp and gamut metadata packets initially and try to
> > write some actual code for them. Those three are the only ones we
> > care about in i915 at the moment.
> 
> Note that I don't have a terribly strong opinion on this, so if using
> one enum instead of two causes more problems than it is worth, then
> that's fine with me as well.
> 
> But you asked, and given a choice with all other things being equal,
> then one enum has my preference.

I do agree that it would seem nicer.

But I'm a bit busy with other things at the moment so I might want
to leave it like this for now and revisit the topic in the
hopefully-not-too-distant future.

> 
> Regards,
> 
> 	Hans
> 
> > 
> >>
> >> Regards,
> >>
> >> 	Hans
> >>
> >>>
> >>> Cc: Thierry Reding <thierry.reding@gmail.com>
> >>> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> >>> Cc: linux-media@vger.kernel.org
> >>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>> ---
> >>>  include/linux/hdmi.h | 15 +++++++++++++++
> >>>  1 file changed, 15 insertions(+)
> >>>
> >>> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> >>> index c76b50a48e48..80521d9591a1 100644
> >>> --- a/include/linux/hdmi.h
> >>> +++ b/include/linux/hdmi.h
> >>> @@ -27,6 +27,21 @@
> >>>  #include <linux/types.h>
> >>>  #include <linux/device.h>
> >>>  
> >>> +enum hdmi_packet_type {
> >>> +	HDMI_PACKET_TYPE_NULL = 0x00,
> >>> +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
> >>> +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
> >>> +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
> >>> +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
> >>> +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
> >>> +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
> >>> +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
> >>> +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
> >>> +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
> >>> +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
> >>> +	/* + enum hdmi_infoframe_type */
> >>> +};
> >>> +
> >>>  enum hdmi_infoframe_type {
> >>>  	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
> >>>  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
> >>>
> > 

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v2 06/18] video/hdmi: Handle the MPEG Source infoframe
  2018-09-20 18:51 ` [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe Ville Syrjala
  2018-09-21  8:28   ` Hans Verkuil
@ 2018-09-21 15:09   ` Ville Syrjala
  1 sibling, 0 replies; 26+ messages in thread
From: Ville Syrjala @ 2018-09-21 15:09 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the code to deal with the MPEG source infoframe.

Blindly typed from the spec, and totally untested.

v2: Rebase

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |  27 ++++++
 2 files changed, 256 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 08d94ab00467..6f39b9ae56b9 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -706,6 +706,131 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
 	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
 }
 
+/**
+ * hdmi_mpeg_source_infoframe_init() - initialize an HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame)
+{
+	memset(frame, 0, sizeof(*frame));
+
+	frame->type = HDMI_INFOFRAME_TYPE_MPEG_SOURCE;
+	frame->version = 1;
+	frame->length = HDMI_MPEG_SOURCE_INFOFRAME_SIZE;
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_init);
+
+static int hdmi_mpeg_source_infoframe_check_only(const struct hdmi_mpeg_source_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_MPEG_SOURCE_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_mpeg_source_infoframe_check() - check a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame)
+{
+	return hdmi_mpeg_source_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_check);
+
+/**
+ * hdmi_mpeg_source_infoframe_pack_only() - write HDMI MPEG Source infoframe to binary buffer
+ * @frame: HDMI MPEG Source 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_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
+					     void *buffer, size_t size)
+{
+	u8 *ptr = buffer;
+	size_t length;
+	int ret;
+
+	ret = hdmi_mpeg_source_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	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 */
+
+	/* start infoframe payload */
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	ptr[0] = frame->mpeg_bit_rate >> 0;
+	ptr[1] = frame->mpeg_bit_rate >> 8;
+	ptr[2] = frame->mpeg_bit_rate >> 16;
+	ptr[3] = frame->mpeg_bit_rate >> 24;
+	ptr[4] = (frame->field_repeat << 4) | frame->mpeg_frame;
+
+	hdmi_infoframe_set_checksum(buffer, length);
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack_only);
+
+/**
+ * hdmi_mpeg_source_infoframe_pack() - check a HDMI MPEG Source infoframe,
+ *                                     and write it to binary buffer
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * 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_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
+					void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_mpeg_source_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_mpeg_source_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
+
 /**
  * hdmi_infoframe_check() - check a HDMI infoframe
  * @frame: HDMI infoframe
@@ -727,6 +852,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
 		return hdmi_audio_infoframe_check(&frame->audio);
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		return hdmi_vendor_any_infoframe_check(&frame->vendor);
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		return -EINVAL;
@@ -770,6 +897,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
 		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
 							     buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
+							      buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -816,6 +947,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
 		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
 							buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
+							 buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -838,6 +973,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_MPEG_SOURCE:
+		return "MPEG Source";
 	}
 	return "Reserved";
 }
@@ -1349,6 +1486,46 @@ hdmi_vendor_any_infoframe_log(const char *level,
 	}
 }
 
+static const char *
+hdmi_mpeg_frame_get_name(enum hdmi_mpeg_frame frame)
+{
+	if (frame < 0 || frame > 3)
+		return "invalid";
+
+	switch (frame) {
+	case HDMI_MPEG_FRAME_UNKNOWN:
+		return "Unknown";
+	case HDMI_MPEG_FRAME_I_PICTURE:
+		return "I Picture";
+	case HDMI_MPEG_FRAME_B_PICTURE:
+		return "B Picture";
+	case HDMI_MPEG_FRAME_P_PICTURE:
+		return "P Picture";
+	}
+	return "Reserved";
+}
+
+/**
+ * hdmi_mpeg_source_infoframe_log() - log info of HDMI MPEG Source infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI MPEG Source infoframe
+ */
+static void hdmi_mpeg_source_infoframe_log(const char *level,
+					   struct device *dev,
+					   const struct hdmi_mpeg_source_infoframe *frame)
+{
+	hdmi_infoframe_log_header(level, dev,
+				  (const struct hdmi_any_infoframe *)frame);
+
+	hdmi_log("    MPEG bit rate: %d Hz\n",
+		 frame->mpeg_bit_rate);
+	hdmi_log("    MPEG frame: %s\n",
+		 hdmi_mpeg_frame_get_name(frame->mpeg_frame));
+	hdmi_log("    field repeat: %s\n",
+		 frame->field_repeat ? "Yes" : "No");
+}
+
 /**
  * hdmi_infoframe_log() - log info of HDMI infoframe
  * @level: logging level
@@ -1372,6 +1549,9 @@ void hdmi_infoframe_log(const char *level,
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
+		break;
 	}
 }
 EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1614,6 +1794,52 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 	return 0;
 }
 
+/**
+ * hdmi_mpeg_source_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI MPEG Source 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_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *frame,
+					     const void *buffer, size_t size)
+{
+	const u8 *ptr = buffer;
+	int ret;
+
+	if (size < HDMI_INFOFRAME_SIZE(MPEG_SOURCE))
+		return -EINVAL;
+
+	if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
+	    ptr[1] != 1 ||
+	    ptr[2] != HDMI_MPEG_SOURCE_INFOFRAME_SIZE) {
+		return -EINVAL;
+	}
+
+	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG_SOURCE)) != 0)
+		return -EINVAL;
+
+	ret = hdmi_mpeg_source_infoframe_init(frame);
+	if (ret)
+		return ret;
+
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	frame->mpeg_bit_rate =
+		(ptr[0] << 0) | (ptr[1] << 8) |
+		(ptr[2] << 16) | (ptr[3] << 24);
+	frame->mpeg_frame = ptr[4] & 0x3;
+	frame->field_repeat = ptr[4] & 0x10;
+
+	return 0;
+}
+
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
  * @frame: HDMI infoframe
@@ -1649,6 +1875,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 80521d9591a1..2c9322f7538d 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_AVI = 0x82,
 	HDMI_INFOFRAME_TYPE_SPD = 0x83,
 	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
+	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
 };
 
 #define HDMI_IEEE_OUI 0x000c03
@@ -55,6 +56,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_MPEG_SOURCE_INFOFRAME_SIZE  10
 
 #define HDMI_INFOFRAME_SIZE(type)	\
 	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
@@ -337,6 +339,29 @@ union hdmi_vendor_any_infoframe {
 	struct hdmi_vendor_infoframe hdmi;
 };
 
+enum hdmi_mpeg_frame {
+	HDMI_MPEG_FRAME_UNKNOWN,
+	HDMI_MPEG_FRAME_I_PICTURE,
+	HDMI_MPEG_FRAME_B_PICTURE,
+	HDMI_MPEG_FRAME_P_PICTURE,
+};
+
+struct hdmi_mpeg_source_infoframe {
+	enum hdmi_infoframe_type type;
+	unsigned char version;
+	unsigned char length;
+	unsigned int mpeg_bit_rate;
+	enum hdmi_mpeg_frame mpeg_frame;
+	bool field_repeat;
+};
+
+int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame);
+ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
+					void *buffer, size_t size);
+ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
+					     void *buffer, size_t size);
+int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
+
 /**
  * union hdmi_infoframe - overall union of all abstract infoframe representations
  * @any: generic infoframe
@@ -344,6 +369,7 @@ union hdmi_vendor_any_infoframe {
  * @spd: spd infoframe
  * @vendor: union of all vendor infoframes
  * @audio: audio infoframe
+ * @mpeg_source: mpeg source infoframe
  *
  * This is used by the generic pack function. This works since all infoframes
  * have the same header which also indicates which type of infoframe should be
@@ -355,6 +381,7 @@ union hdmi_infoframe {
 	struct hdmi_spd_infoframe spd;
 	union hdmi_vendor_any_infoframe vendor;
 	struct hdmi_audio_infoframe audio;
+	struct hdmi_mpeg_source_infoframe mpeg_source;
 };
 
 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v2 07/18] video/hdmi: Handle the NTSC VBI infoframe
  2018-09-20 18:51 ` [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe Ville Syrjala
  2018-09-21  8:30   ` Hans Verkuil
@ 2018-09-21 15:10   ` Ville Syrjala
  1 sibling, 0 replies; 26+ messages in thread
From: Ville Syrjala @ 2018-09-21 15:10 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the code to deal with the NTSC VBI infoframe.

I decided against parsing the PES_data_field and just leave
it as an opaque blob, just dumping it out as hex in the log.

Blindly typed from the spec, and totally untested.

v2: Rebase

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |  18 +++++
 2 files changed, 226 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 6f39b9ae56b9..b14202fc5854 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -831,6 +831,139 @@ ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame
 }
 EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
 
+/**
+ * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI NTSC VBI infoframe
+ * @frame: HDMI NTSC VBI infoframe
+ * @pes_data_field: ANSI/SCTE 127 PES_data_field
+ * @length: ANSI/SCTE 127 PES_data_field length
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
+				 const void *pes_data_field,
+				 size_t length)
+{
+	if (length < 1 || length > 27)
+		return -EINVAL;
+
+	memset(frame, 0, sizeof(*frame));
+
+	frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
+	frame->version = 1;
+	frame->length = length;
+
+	memcpy(frame->pes_data_field, pes_data_field, length);
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
+
+static int hdmi_ntsc_vbi_infoframe_check_only(const struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+	    frame->version != 1 ||
+	    frame->length < 1 || frame->length > 27)
+		return -EINVAL;
+
+	if (frame->pes_data_field[0] != 0x99)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_ntsc_vbi_infoframe_check() - Check and check a HDMI NTSC VBI infoframe
+ * @frame: HDMI NTSC VBI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	return hdmi_ntsc_vbi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_check);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack_only() - write HDMI NTSC VBI 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_only(const struct hdmi_ntsc_vbi_infoframe *frame,
+					  void *buffer, size_t size)
+{
+	u8 *ptr = buffer;
+	size_t length;
+	int ret;
+
+	ret = hdmi_ntsc_vbi_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	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 */
+
+	/* start infoframe payload */
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	memcpy(ptr, frame->pes_data_field, frame->length);
+
+	hdmi_infoframe_set_checksum(buffer, length);
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack_only);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack() - check a HDMI NTSC VBI infoframe,
+ *                                  and write it to binary buffer
+ * @frame: HDMI NTSC VBI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * 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)
+{
+	int ret;
+
+	ret = hdmi_ntsc_vbi_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_ntsc_vbi_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
+
 /**
  * hdmi_infoframe_check() - check a HDMI infoframe
  * @frame: HDMI infoframe
@@ -854,6 +987,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
 		return hdmi_vendor_any_infoframe_check(&frame->vendor);
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		return -EINVAL;
@@ -901,6 +1036,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
 		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
 							      buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		length = hdmi_ntsc_vbi_infoframe_pack_only(&frame->ntsc_vbi,
+							   buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -951,6 +1090,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
 		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
 							 buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi,
+						      buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -975,6 +1118,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 		return "Audio";
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		return "MPEG Source";
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		return "NTSC VBI";
 	}
 	return "Reserved";
 }
@@ -1526,6 +1671,22 @@ static void hdmi_mpeg_source_infoframe_log(const char *level,
 		 frame->field_repeat ? "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,
+					const struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	hdmi_infoframe_log_header(level, dev,
+				  (const struct hdmi_any_infoframe *)frame);
+
+	hdmi_log("    %*ph\n", frame->length, frame->pes_data_field);
+}
+
 /**
  * hdmi_infoframe_log() - log info of HDMI infoframe
  * @level: logging level
@@ -1552,6 +1713,9 @@ void hdmi_infoframe_log(const char *level,
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
+		break;
 	}
 }
 EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1840,6 +2004,47 @@ static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *
 	return 0;
 }
 
+/**
+ * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI MPEG Source 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,
+					  const void *buffer, size_t size)
+{
+	const u8 *ptr = buffer;
+	size_t length;
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+
+	if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+	    ptr[1] != 1 ||
+	    ptr[2] < 1 || ptr[2] > 27)
+		return -EINVAL;
+
+	length = ptr[2];
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
+		return -EINVAL;
+
+	if (hdmi_infoframe_checksum(buffer,
+				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
+		return -EINVAL;
+
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	return hdmi_ntsc_vbi_infoframe_init(frame, ptr, length);
+}
+
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
  * @frame: HDMI infoframe
@@ -1878,6 +2083,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer, size);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 2c9322f7538d..3821516b336c 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -48,6 +48,7 @@ enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_SPD = 0x83,
 	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
 	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
+	HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
 };
 
 #define HDMI_IEEE_OUI 0x000c03
@@ -362,6 +363,21 @@ ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infof
 					     void *buffer, size_t size);
 int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
 
+struct hdmi_ntsc_vbi_infoframe {
+	enum hdmi_infoframe_type type;
+	unsigned char version;
+	unsigned char length;
+	unsigned char pes_data_field[27];
+};
+
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
+				 const void *pes_data_field, size_t length);
+ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
+				     void *buffer, size_t size);
+ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
+					  void *buffer, size_t size);
+int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame);
+
 /**
  * union hdmi_infoframe - overall union of all abstract infoframe representations
  * @any: generic infoframe
@@ -370,6 +386,7 @@ int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
  * @vendor: union of all vendor infoframes
  * @audio: audio infoframe
  * @mpeg_source: mpeg source infoframe
+ * @ntsc_vbi: ntsc vbi infoframe
  *
  * This is used by the generic pack function. This works since all infoframes
  * have the same header which also indicates which type of infoframe should be
@@ -382,6 +399,7 @@ union hdmi_infoframe {
 	union hdmi_vendor_any_infoframe vendor;
 	struct hdmi_audio_infoframe audio;
 	struct hdmi_mpeg_source_infoframe mpeg_source;
+	struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
 };
 
 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 04/18] video/hdmi: Constify infoframe passed to the pack functions
  2018-09-21 14:33   ` [PATCH v3 " Ville Syrjala
@ 2018-10-01 19:10     ` Ville Syrjälä
  2018-10-02  6:37       ` Hans Verkuil
  0 siblings, 1 reply; 26+ messages in thread
From: Ville Syrjälä @ 2018-10-01 19:10 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 05:33:32PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Let's make the infoframe pack functions usable with a const infoframe
> structure. This allows us to precompute the infoframe earlier, and still
> pack it later when we're no longer allowed to modify the structure.
> So now we end up with a _check()+_pack_only() or _pack() functions
> depending on whether you want to precompute the infoframes or not.
> The names aren't great but I was lazy and didn't want to change all the
> drivers.
> 
> v2: Deal with exynos churn
>     Actually export the new funcs
> v3: Fix various documentation fails (Hans)

Hans, any more concerns about this patch?

> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
>  include/linux/hdmi.h |  19 ++-
>  2 files changed, 416 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 53e7ee2c83fc..08d94ab00467 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
>  }
>  EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>  
> +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
> +	    frame->version != 2 ||
> +	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
> + * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
> + * @frame: HDMI AVI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
> +{
> +	return hdmi_avi_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_avi_infoframe_check);
> +
> +/**
> + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
>   * @frame: HDMI AVI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> -				size_t size)
> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> +				     void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_avi_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
>  	if (size < length)
>  		return -ENOSPC;
>  
> -	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> -		return -EINVAL;
> -
>  	memset(buffer, 0, size);
>  
>  	ptr[0] = frame->type;
> @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
> +
> +/**
> + * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
> + *                             and write it to binary buffer
> + * @frame: HDMI AVI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * 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_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
> +				void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_avi_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
>  
>  /**
> @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>  }
>  EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>  
> +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
> + * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
> + * @frame: HDMI SPD infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
> +{
> +	return hdmi_spd_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_spd_infoframe_check);
> +
> +/**
> + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
>   * @frame: HDMI SPD infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> -				size_t size)
> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> +				     void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_spd_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
> +
> +/**
> + * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
> + *                             and write it to binary buffer
> + * @frame: HDMI SPD infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * 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_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
> +				void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_spd_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
>  
>  /**
> @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
>  }
>  EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>  
> +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
> + * @frame: HDMI audio infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
> +{
> +	return hdmi_audio_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_audio_infoframe_check);
> +
>  /**
> - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
> + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
>   * @frame: HDMI audio infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> -				  void *buffer, size_t size)
> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> +				       void *buffer, size_t size)
>  {
>  	unsigned char channels;
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_audio_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
> +
> +/**
> + * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
> + *                               and write it to binary buffer
> + * @frame: HDMI Audio infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * 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_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> +				  void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_audio_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
>  
>  /**
> @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
>  	 * value
>  	 */
>  	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
> +	frame->length = 4;
>  
>  	return 0;
>  }
> @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>  		return 4;
>  }
>  
> +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
> +	    frame->version != 1 ||
> +	    frame->oui != HDMI_IEEE_OUI)
> +		return -EINVAL;
> +
> +	/* only one of those can be supplied */
> +	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> +		return -EINVAL;
> +
> +	if (frame->length != hdmi_vendor_infoframe_length(frame))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
> + * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
> + * @frame: HDMI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
> +{
> +	frame->length = hdmi_vendor_infoframe_length(frame);
> +
> +	return hdmi_vendor_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
> +
> +/**
> + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
>   * @frame: HDMI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> -				 void *buffer, size_t size)
> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> +					void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
>  
> -	/* only one of those can be supplied */
> -	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> -		return -EINVAL;
> -
> -	frame->length = hdmi_vendor_infoframe_length(frame);
> +	ret = hdmi_vendor_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
> +
> +/**
> + * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
> + *                                and write it to binary buffer
> + * @frame: HDMI Vendor infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * 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_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> +				   void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
>  
> +static int
> +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
> +{
> +	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
> +	    frame->any.version != 1)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /*
> - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
> + * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
> + */
> +static int
> +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
> +	/* we only know about HDMI vendor infoframes */
> +	if (frame->any.oui != HDMI_IEEE_OUI)
> +		return -EINVAL;
> +
> +	return hdmi_vendor_infoframe_check(&frame->hdmi);
> +}
> +
> +/*
> + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
>   */
>  static ssize_t
> -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> -			   void *buffer, size_t size)
> +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
> +				    void *buffer, size_t size)
>  {
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
>  	/* we only know about HDMI vendor infoframes */
>  	if (frame->any.oui != HDMI_IEEE_OUI)
>  		return -EINVAL;
>  
> -	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
> +	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
> +}
> +
> +/*
> + * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
> + *                                    and write it to binary buffer
> + */
> +static ssize_t
> +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> +			       void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
> +}
> +
> +/**
> + * hdmi_infoframe_check() - check a HDMI infoframe
> + * @frame: HDMI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int
> +hdmi_infoframe_check(union hdmi_infoframe *frame)
> +{
> +	switch (frame->any.type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		return hdmi_avi_infoframe_check(&frame->avi);
> +	case HDMI_INFOFRAME_TYPE_SPD:
> +		return hdmi_spd_infoframe_check(&frame->spd);
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		return hdmi_audio_infoframe_check(&frame->audio);
> +	case HDMI_INFOFRAME_TYPE_VENDOR:
> +		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> +	default:
> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> +		return -EINVAL;
> +	}
>  }
> +EXPORT_SYMBOL(hdmi_infoframe_check);
>  
>  /**
> - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
> + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
>   * @frame: HDMI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>   * error code on failure.
>   */
>  ssize_t
> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
> +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
> +{
> +	ssize_t length;
> +
> +	switch (frame->any.type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		length = hdmi_avi_infoframe_pack_only(&frame->avi,
> +						      buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_SPD:
> +		length = hdmi_spd_infoframe_pack_only(&frame->spd,
> +						      buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		length = hdmi_audio_infoframe_pack_only(&frame->audio,
> +							buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_VENDOR:
> +		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
> +							     buffer, size);
> +		break;
> +	default:
> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> +		length = -EINVAL;
> +	}
> +
> +	return length;
> +}
> +EXPORT_SYMBOL(hdmi_infoframe_pack_only);
> +
> +/**
> + * hdmi_infoframe_pack() - check a HDMI infoframe,
> + *                         and write it to binary buffer
> + * @frame: HDMI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * 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_infoframe_pack(union hdmi_infoframe *frame,
> +		    void *buffer, size_t size)
>  {
>  	ssize_t length;
>  
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index bce1abb1fe57..c76b50a48e48 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
>  int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
>  ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>  				size_t size);
> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> +				     void *buffer, size_t size);
> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
>  
>  enum hdmi_spd_sdi {
>  	HDMI_SPD_SDI_UNKNOWN,
> @@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>  			    const char *vendor, const char *product);
>  ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>  				size_t size);
> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> +				     void *buffer, size_t size);
> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
>  
>  enum hdmi_audio_coding_type {
>  	HDMI_AUDIO_CODING_TYPE_STREAM,
> @@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
>  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);
> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> +				       void *buffer, size_t size);
> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
>  
>  enum hdmi_3d_structure {
>  	HDMI_3D_STRUCTURE_INVALID = -1,
> @@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
>  int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
>  ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>  				   void *buffer, size_t size);
> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> +					void *buffer, size_t size);
> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
>  
>  union hdmi_vendor_any_infoframe {
>  	struct {
> @@ -330,8 +342,11 @@ union hdmi_infoframe {
>  	struct hdmi_audio_infoframe audio;
>  };
>  
> -ssize_t
> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
> +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> +			    size_t size);
> +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
> +				 void *buffer, size_t size);
> +int hdmi_infoframe_check(union hdmi_infoframe *frame);
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  			  const void *buffer, size_t size);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
> -- 
> 2.16.4

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 04/18] video/hdmi: Constify infoframe passed to the pack functions
  2018-10-01 19:10     ` Ville Syrjälä
@ 2018-10-02  6:37       ` Hans Verkuil
  0 siblings, 0 replies; 26+ messages in thread
From: Hans Verkuil @ 2018-10-02  6:37 UTC (permalink / raw)
  To: Ville Syrjälä, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 10/01/2018 09:10 PM, Ville Syrjälä wrote:
> On Fri, Sep 21, 2018 at 05:33:32PM +0300, Ville Syrjala wrote:
>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>
>> Let's make the infoframe pack functions usable with a const infoframe
>> structure. This allows us to precompute the infoframe earlier, and still
>> pack it later when we're no longer allowed to modify the structure.
>> So now we end up with a _check()+_pack_only() or _pack() functions
>> depending on whether you want to precompute the infoframes or not.
>> The names aren't great but I was lazy and didn't want to change all the
>> drivers.
>>
>> v2: Deal with exynos churn
>>     Actually export the new funcs
>> v3: Fix various documentation fails (Hans)
> 
> Hans, any more concerns about this patch?

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Regards,

	Hans

> 
>>
>> Cc: Thierry Reding <thierry.reding@gmail.com>
>> Cc: Hans Verkuil <hans.verkuil@cisco.com>
>> Cc: linux-media@vger.kernel.org
>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> ---
>>  drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
>>  include/linux/hdmi.h |  19 ++-
>>  2 files changed, 416 insertions(+), 28 deletions(-)
>>
>> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
>> index 53e7ee2c83fc..08d94ab00467 100644
>> --- a/drivers/video/hdmi.c
>> +++ b/drivers/video/hdmi.c
>> @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
>>  }
>>  EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>>  
>> +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
>> +{
>> +	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
>> +	    frame->version != 2 ||
>> +	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
>> +		return -EINVAL;
>> +
>> +	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /**
>> - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
>> + * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
>> + * @frame: HDMI AVI infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
>> +{
>> +	return hdmi_avi_infoframe_check_only(frame);
>> +}
>> +EXPORT_SYMBOL(hdmi_avi_infoframe_check);
>> +
>> +/**
>> + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
>>   * @frame: HDMI AVI infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>>   * Returns the number of bytes packed into the binary buffer or a negative
>>   * error code on failure.
>>   */
>> -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>> -				size_t size)
>> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
>> +				     void *buffer, size_t size)
>>  {
>>  	u8 *ptr = buffer;
>>  	size_t length;
>> +	int ret;
>> +
>> +	ret = hdmi_avi_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>>  
>>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>>  
>>  	if (size < length)
>>  		return -ENOSPC;
>>  
>> -	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
>> -		return -EINVAL;
>> -
>>  	memset(buffer, 0, size);
>>  
>>  	ptr[0] = frame->type;
>> @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>>  
>>  	return length;
>>  }
>> +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
>> + *                             and write it to binary buffer
>> + * @frame: HDMI AVI infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * 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_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
>> +				void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_avi_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
>> +}
>>  EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
>>  
>>  /**
>> @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>>  }
>>  EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>>  
>> +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
>> +{
>> +	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
>> +	    frame->version != 1 ||
>> +	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /**
>> - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
>> + * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
>> + * @frame: HDMI SPD infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
>> +{
>> +	return hdmi_spd_infoframe_check_only(frame);
>> +}
>> +EXPORT_SYMBOL(hdmi_spd_infoframe_check);
>> +
>> +/**
>> + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
>>   * @frame: HDMI SPD infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>>   * Returns the number of bytes packed into the binary buffer or a negative
>>   * error code on failure.
>>   */
>> -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>> -				size_t size)
>> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
>> +				     void *buffer, size_t size)
>>  {
>>  	u8 *ptr = buffer;
>>  	size_t length;
>> +	int ret;
>> +
>> +	ret = hdmi_spd_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>>  
>>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>>  
>> @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>>  
>>  	return length;
>>  }
>> +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
>> + *                             and write it to binary buffer
>> + * @frame: HDMI SPD infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * 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_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
>> +				void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_spd_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
>> +}
>>  EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
>>  
>>  /**
>> @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
>>  }
>>  EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>>  
>> +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
>> +{
>> +	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
>> +	    frame->version != 1 ||
>> +	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
>> + * @frame: HDMI audio infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
>> +{
>> +	return hdmi_audio_infoframe_check_only(frame);
>> +}
>> +EXPORT_SYMBOL(hdmi_audio_infoframe_check);
>> +
>>  /**
>> - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
>> + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
>>   * @frame: HDMI audio infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>>   * Returns the number of bytes packed into the binary buffer or a negative
>>   * error code on failure.
>>   */
>> -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>> -				  void *buffer, size_t size)
>> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
>> +				       void *buffer, size_t size)
>>  {
>>  	unsigned char channels;
>>  	u8 *ptr = buffer;
>>  	size_t length;
>> +	int ret;
>> +
>> +	ret = hdmi_audio_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>>  
>>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>>  
>> @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>>  
>>  	return length;
>>  }
>> +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
>> + *                               and write it to binary buffer
>> + * @frame: HDMI Audio infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * 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_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>> +				  void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_audio_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
>> +}
>>  EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
>>  
>>  /**
>> @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
>>  	 * value
>>  	 */
>>  	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
>> +	frame->length = 4;
>>  
>>  	return 0;
>>  }
>> @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>>  		return 4;
>>  }
>>  
>> +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
>> +{
>> +	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
>> +	    frame->version != 1 ||
>> +	    frame->oui != HDMI_IEEE_OUI)
>> +		return -EINVAL;
>> +
>> +	/* only one of those can be supplied */
>> +	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
>> +		return -EINVAL;
>> +
>> +	if (frame->length != hdmi_vendor_infoframe_length(frame))
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /**
>> - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
>> + * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
>> + * @frame: HDMI infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
>> +{
>> +	frame->length = hdmi_vendor_infoframe_length(frame);
>> +
>> +	return hdmi_vendor_infoframe_check_only(frame);
>> +}
>> +EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
>> +
>> +/**
>> + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
>>   * @frame: HDMI infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>>   * Returns the number of bytes packed into the binary buffer or a negative
>>   * error code on failure.
>>   */
>> -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>> -				 void *buffer, size_t size)
>> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
>> +					void *buffer, size_t size)
>>  {
>>  	u8 *ptr = buffer;
>>  	size_t length;
>> +	int ret;
>>  
>> -	/* only one of those can be supplied */
>> -	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
>> -		return -EINVAL;
>> -
>> -	frame->length = hdmi_vendor_infoframe_length(frame);
>> +	ret = hdmi_vendor_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>>  
>>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>>  
>> @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>>  
>>  	return length;
>>  }
>> +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
>> + *                                and write it to binary buffer
>> + * @frame: HDMI Vendor infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * 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_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>> +				   void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_vendor_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
>> +}
>>  EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
>>  
>> +static int
>> +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
>> +{
>> +	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
>> +	    frame->any.version != 1)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /*
>> - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
>> + * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
>> + */
>> +static int
>> +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* we only know about HDMI vendor infoframes */
>> +	if (frame->any.oui != HDMI_IEEE_OUI)
>> +		return -EINVAL;
>> +
>> +	return hdmi_vendor_infoframe_check(&frame->hdmi);
>> +}
>> +
>> +/*
>> + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
>>   */
>>  static ssize_t
>> -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>> -			   void *buffer, size_t size)
>> +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
>> +				    void *buffer, size_t size)
>>  {
>> +	int ret;
>> +
>> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>> +
>>  	/* we only know about HDMI vendor infoframes */
>>  	if (frame->any.oui != HDMI_IEEE_OUI)
>>  		return -EINVAL;
>>  
>> -	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
>> +	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
>> +}
>> +
>> +/*
>> + * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
>> + *                                    and write it to binary buffer
>> + */
>> +static ssize_t
>> +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>> +			       void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_vendor_any_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
>> +}
>> +
>> +/**
>> + * hdmi_infoframe_check() - check a HDMI infoframe
>> + * @frame: HDMI infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int
>> +hdmi_infoframe_check(union hdmi_infoframe *frame)
>> +{
>> +	switch (frame->any.type) {
>> +	case HDMI_INFOFRAME_TYPE_AVI:
>> +		return hdmi_avi_infoframe_check(&frame->avi);
>> +	case HDMI_INFOFRAME_TYPE_SPD:
>> +		return hdmi_spd_infoframe_check(&frame->spd);
>> +	case HDMI_INFOFRAME_TYPE_AUDIO:
>> +		return hdmi_audio_infoframe_check(&frame->audio);
>> +	case HDMI_INFOFRAME_TYPE_VENDOR:
>> +		return hdmi_vendor_any_infoframe_check(&frame->vendor);
>> +	default:
>> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>> +		return -EINVAL;
>> +	}
>>  }
>> +EXPORT_SYMBOL(hdmi_infoframe_check);
>>  
>>  /**
>> - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
>> + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
>>   * @frame: HDMI infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>>   * error code on failure.
>>   */
>>  ssize_t
>> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
>> +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
>> +{
>> +	ssize_t length;
>> +
>> +	switch (frame->any.type) {
>> +	case HDMI_INFOFRAME_TYPE_AVI:
>> +		length = hdmi_avi_infoframe_pack_only(&frame->avi,
>> +						      buffer, size);
>> +		break;
>> +	case HDMI_INFOFRAME_TYPE_SPD:
>> +		length = hdmi_spd_infoframe_pack_only(&frame->spd,
>> +						      buffer, size);
>> +		break;
>> +	case HDMI_INFOFRAME_TYPE_AUDIO:
>> +		length = hdmi_audio_infoframe_pack_only(&frame->audio,
>> +							buffer, size);
>> +		break;
>> +	case HDMI_INFOFRAME_TYPE_VENDOR:
>> +		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
>> +							     buffer, size);
>> +		break;
>> +	default:
>> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>> +		length = -EINVAL;
>> +	}
>> +
>> +	return length;
>> +}
>> +EXPORT_SYMBOL(hdmi_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_infoframe_pack() - check a HDMI infoframe,
>> + *                         and write it to binary buffer
>> + * @frame: HDMI infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * 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_infoframe_pack(union hdmi_infoframe *frame,
>> +		    void *buffer, size_t size)
>>  {
>>  	ssize_t length;
>>  
>> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
>> index bce1abb1fe57..c76b50a48e48 100644
>> --- a/include/linux/hdmi.h
>> +++ b/include/linux/hdmi.h
>> @@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
>>  int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
>>  ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>>  				size_t size);
>> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
>> +				     void *buffer, size_t size);
>> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
>>  
>>  enum hdmi_spd_sdi {
>>  	HDMI_SPD_SDI_UNKNOWN,
>> @@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>>  			    const char *vendor, const char *product);
>>  ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>>  				size_t size);
>> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
>> +				     void *buffer, size_t size);
>> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
>>  
>>  enum hdmi_audio_coding_type {
>>  	HDMI_AUDIO_CODING_TYPE_STREAM,
>> @@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
>>  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);
>> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
>> +				       void *buffer, size_t size);
>> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
>>  
>>  enum hdmi_3d_structure {
>>  	HDMI_3D_STRUCTURE_INVALID = -1,
>> @@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
>>  int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
>>  ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>>  				   void *buffer, size_t size);
>> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
>> +					void *buffer, size_t size);
>> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
>>  
>>  union hdmi_vendor_any_infoframe {
>>  	struct {
>> @@ -330,8 +342,11 @@ union hdmi_infoframe {
>>  	struct hdmi_audio_infoframe audio;
>>  };
>>  
>> -ssize_t
>> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
>> +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
>> +			    size_t size);
>> +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
>> +				 void *buffer, size_t size);
>> +int hdmi_infoframe_check(union hdmi_infoframe *frame);
>>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>>  			  const void *buffer, size_t size);
>>  void hdmi_infoframe_log(const char *level, struct device *dev,
>> -- 
>> 2.16.4
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2018-10-02 13:19 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-20 18:51 [PATCH 00/18] drm/i915: Infoframe precompute/check Ville Syrjala
2018-09-20 18:51 ` [PATCH 01/18] video/hdmi: Constify 'buffer' to the unpack functions Ville Syrjala
2018-09-21  8:03   ` Hans Verkuil
2018-09-20 18:51 ` [PATCH 02/18] video/hdmi: Pass buffer size to infoframe " Ville Syrjala
2018-09-21  8:06   ` Hans Verkuil
2018-09-20 18:51 ` [PATCH 03/18] video/hdmi: Constify infoframe passed to the log functions Ville Syrjala
2018-09-21  8:06   ` Hans Verkuil
2018-09-20 18:51 ` [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions Ville Syrjala
2018-09-21  8:24   ` Hans Verkuil
2018-09-21 14:30     ` Ville Syrjälä
2018-09-21 14:33   ` [PATCH v3 " Ville Syrjala
2018-10-01 19:10     ` Ville Syrjälä
2018-10-02  6:37       ` Hans Verkuil
2018-09-20 18:51 ` [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types Ville Syrjala
2018-09-21  8:41   ` Hans Verkuil
2018-09-21 14:01     ` Ville Syrjälä
2018-09-21 14:12       ` Hans Verkuil
2018-09-21 15:07         ` Ville Syrjälä
2018-09-20 18:51 ` [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe Ville Syrjala
2018-09-21  8:28   ` Hans Verkuil
2018-09-21 13:53     ` Ville Syrjälä
2018-09-21 15:09   ` [PATCH v2 " Ville Syrjala
2018-09-20 18:51 ` [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe Ville Syrjala
2018-09-21  8:30   ` Hans Verkuil
2018-09-21 13:54     ` Ville Syrjälä
2018-09-21 15:10   ` [PATCH v2 " Ville Syrjala

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).