Module Name:    src
Committed By:   riastradh
Date:           Sun Dec 19 11:45:35 UTC 2021

Modified Files:
        src/sys/external/bsd/drm2/include/linux: hdmi.h

Log Message:
linux/hdmi: Update.  Add unpack.


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/external/bsd/drm2/include/linux/hdmi.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/drm2/include/linux/hdmi.h
diff -u src/sys/external/bsd/drm2/include/linux/hdmi.h:1.13 src/sys/external/bsd/drm2/include/linux/hdmi.h:1.14
--- src/sys/external/bsd/drm2/include/linux/hdmi.h:1.13	Sun Dec 19 11:45:27 2021
+++ src/sys/external/bsd/drm2/include/linux/hdmi.h	Sun Dec 19 11:45:35 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: hdmi.h,v 1.13 2021/12/19 11:45:27 riastradh Exp $	*/
+/*	$NetBSD: hdmi.h,v 1.14 2021/12/19 11:45:35 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -38,28 +38,29 @@
 #include <sys/systm.h>
 
 enum hdmi_3d_structure {
-        HDMI_3D_STRUCTURE_INVALID		= -1,
-        HDMI_3D_STRUCTURE_FRAME_PACKING		= 0,
-        HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE	= 1,
-        HDMI_3D_STRUCTURE_LINE_ALTERNATIVE	= 2,
-        HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL	= 3,
-        HDMI_3D_STRUCTURE_L_DEPTH		= 4,
-        HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH	= 5,
-        HDMI_3D_STRUCTURE_TOP_AND_BOTTOM	= 6,
-        HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF	= 8,
+	HDMI_3D_STRUCTURE_INVALID		= -1,
+	HDMI_3D_STRUCTURE_FRAME_PACKING		= 0,
+	HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE	= 1,
+	HDMI_3D_STRUCTURE_LINE_ALTERNATIVE	= 2,
+	HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL	= 3,
+	HDMI_3D_STRUCTURE_L_DEPTH		= 4,
+	HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH	= 5,
+	HDMI_3D_STRUCTURE_TOP_AND_BOTTOM	= 6,
+	HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF	= 8,
 };
 
 enum hdmi_active_aspect {
-        HDMI_ACTIVE_ASPECT_16_9_TOP		= 2,
-        HDMI_ACTIVE_ASPECT_14_9_TOP		= 3,
-        HDMI_ACTIVE_ASPECT_16_9_CENTER		= 4,
-        HDMI_ACTIVE_ASPECT_PICTURE		= 8,
-        HDMI_ACTIVE_ASPECT_4_3			= 9,
-        HDMI_ACTIVE_ASPECT_16_9			= 10,
-        HDMI_ACTIVE_ASPECT_14_9			= 11,
-        HDMI_ACTIVE_ASPECT_4_3_SP_14_9		= 13,
-        HDMI_ACTIVE_ASPECT_16_9_SP_14_9		= 14,
-        HDMI_ACTIVE_ASPECT_16_9_SP_4_3		= 15,
+	HDMI_ACTIVE_ASPECT_NONE			= 0,
+	HDMI_ACTIVE_ASPECT_16_9_TOP		= 2,
+	HDMI_ACTIVE_ASPECT_14_9_TOP		= 3,
+	HDMI_ACTIVE_ASPECT_16_9_CENTER		= 4,
+	HDMI_ACTIVE_ASPECT_PICTURE		= 8,
+	HDMI_ACTIVE_ASPECT_4_3			= 9,
+	HDMI_ACTIVE_ASPECT_16_9			= 10,
+	HDMI_ACTIVE_ASPECT_14_9			= 11,
+	HDMI_ACTIVE_ASPECT_4_3_SP_14_9		= 13,
+	HDMI_ACTIVE_ASPECT_16_9_SP_14_9		= 14,
+	HDMI_ACTIVE_ASPECT_16_9_SP_4_3		= 15,
 };
 
 enum hdmi_audio_coding_type {
@@ -116,6 +117,8 @@ enum hdmi_colorspace {
 	HDMI_COLORSPACE_RGB			= 0,
 	HDMI_COLORSPACE_YUV422			= 1,
 	HDMI_COLORSPACE_YUV444			= 2,
+	HDMI_COLORSPACE_YUV420			= 3,
+	HDMI_COLORSPACE_IDO_DEFINED		= 7,
 };
 
 enum hdmi_content_type {
@@ -129,8 +132,8 @@ enum hdmi_extended_colorimetry {
 	HDMI_EXTENDED_COLORIMETRY_XV_YCC_601	= 0,
 	HDMI_EXTENDED_COLORIMETRY_XV_YCC_709	= 1,
 	HDMI_EXTENDED_COLORIMETRY_S_YCC_601	= 2,
-	HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601	= 3,
-	HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB	= 4,
+	HDMI_EXTENDED_COLORIMETRY_OPYCC_601	= 3,
+	HDMI_EXTENDED_COLORIMETRY_OPRGB		= 4,
 };
 
 enum hdmi_nups {
@@ -189,14 +192,14 @@ enum hdmi_infoframe_type {
 };
 
 enum hdmi_eotf {
-	HDMI_EOTF_TRADITIONAL_GAMMA_SDR,
-	HDMI_EOTF_TRADITIONAL_GAMMA_HDR,
-	HDMI_EOTF_SMPTE_ST2084,
-	HDMI_EOTF_BT_2100_HLG,
+	HDMI_EOTF_TRADITIONAL_GAMMA_SDR		= 0,
+	HDMI_EOTF_TRADITIONAL_GAMMA_HDR		= 1,
+	HDMI_EOTF_SMPTE_ST2084			= 2,
+	HDMI_EOTF_BT_2100_HLG			= 3,
 };
 
 enum hdmi_metadata_type {
-	HDMI_STATIC_METADATA_TYPE1 = 1,
+	HDMI_STATIC_METADATA_TYPE1		= 1,
 };
 
 struct hdmi_type1 {
@@ -233,6 +236,18 @@ hdmi_infoframe_header_init(struct hdmi_i
 }
 
 static inline int
+hdmi_infoframe_header_check(const struct hdmi_infoframe_header *header,
+    enum hdmi_infoframe_type type, uint8_t vers, uint8_t length)
+{
+
+	if (header->type != type ||
+	    header->version != vers ||
+	    header->length != length)
+		return -EINVAL;
+	return 0;
+}
+
+static inline int
 hdmi_infoframe_header_pack(const struct hdmi_infoframe_header *header,
     uint8_t length, void *buf, size_t size)
 {
@@ -251,17 +266,41 @@ hdmi_infoframe_header_pack(const struct 
 	return HDMI_INFOFRAME_HEADER_SIZE;
 }
 
-static inline void
-hdmi_infoframe_checksum(void *buf, size_t length)
+static inline uint8_t
+hdmi_infoframe_checksum(const void *buf, size_t length)
 {
-	uint8_t *p = buf;
+	const uint8_t *p = buf;
 	uint8_t checksum = 0;
 
 	while (length--)
 		checksum += *p++;
 
-	p = buf;
-	p[3] = (256 - checksum);
+	return 256 - checksum;
+}
+
+static inline int
+hdmi_infoframe_header_unpack(struct hdmi_infoframe_header *header,
+    const void *buf, size_t size)
+{
+	const uint8_t *const p = buf;
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+	if (p[2] > size - HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+	if (hdmi_infoframe_checksum(buf, p[2] + HDMI_INFOFRAME_HEADER_SIZE))
+		return -EINVAL;
+
+	hdmi_infoframe_header_init(header, p[0], p[1], p[2]);
+	return HDMI_INFOFRAME_HEADER_SIZE;
+}
+
+static inline void
+hdmi_infoframe_set_checksum(void *buf, size_t length)
+{
+	uint8_t *p = buf;
+
+	p[3] = hdmi_infoframe_checksum(buf, length);
 }
 
 #define	HDMI_AUDIO_INFOFRAME_SIZE	10
@@ -320,7 +359,7 @@ hdmi_audio_infoframe_pack(const struct h
 
 	p[2] = __SHIFTIN(frame->coding_type_ext, __BITS(5,0));
 
-	p[3] = __SHIFTIN(frame->level_shift_value, __BITS(6, 3));
+	p[3] = __SHIFTIN(frame->level_shift_value, __BITS(6,3));
 
 	p[4] = __SHIFTIN(frame->downmix_inhibit? 1 : 0, __BIT(7));
 
@@ -333,11 +372,43 @@ hdmi_audio_infoframe_pack(const struct h
 
 	CTASSERT(HDMI_AUDIO_INFOFRAME_SIZE == 10);
 
-	hdmi_infoframe_checksum(buf, length);
+	hdmi_infoframe_set_checksum(buf, length);
 
 	return length;
 }
 
+static inline int
+hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
+    const void *buf, size_t size)
+{
+	const uint8_t *p = buf;
+	int ret;
+
+	memset(frame, 0, sizeof(*frame));
+
+	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
+	if (ret)
+		return ret;
+	if (frame->header.length != HDMI_AUDIO_INFOFRAME_SIZE)
+		return -EINVAL;
+	p += HDMI_INFOFRAME_HEADER_SIZE;
+	size -= HDMI_INFOFRAME_HEADER_SIZE;
+
+	frame->coding_type = __SHIFTOUT(p[0], __BITS(7,4));
+	frame->channels = __SHIFTOUT(p[0], __BITS(2,0));
+
+	frame->sample_frequency = __SHIFTOUT(p[1], __BITS(4,2));
+	frame->sample_size = __SHIFTOUT(p[1], __BITS(1,0));
+
+	frame->coding_type_ext = __SHIFTOUT(p[2], __BITS(5,0));
+
+	frame->level_shift_value = __SHIFTOUT(p[3], __BITS(6,3));
+
+	frame->downmix_inhibit = __SHIFTOUT(p[4], __BIT(7));
+
+	return 0;
+}
+
 #define	HDMI_AVI_INFOFRAME_SIZE		13
 struct hdmi_avi_infoframe {
 	struct hdmi_infoframe_header	header;
@@ -373,6 +444,19 @@ hdmi_avi_infoframe_init(struct hdmi_avi_
 	return 0;
 }
 
+static inline int
+hdmi_avi_infoframe_check(const struct hdmi_avi_infoframe *frame)
+{
+	int ret;
+
+	ret = hdmi_infoframe_header_check(&frame->header,
+	    HDMI_INFOFRAME_TYPE_AVI, 2, HDMI_AVI_INFOFRAME_SIZE);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 static inline ssize_t
 hdmi_avi_infoframe_pack(const struct hdmi_avi_infoframe *frame, void *buf,
     size_t size)
@@ -418,11 +502,176 @@ hdmi_avi_infoframe_pack(const struct hdm
 	le16enc(&p[11], frame->right_bar);
 	CTASSERT(HDMI_AVI_INFOFRAME_SIZE == 13);
 
-	hdmi_infoframe_checksum(buf, length);
+	hdmi_infoframe_set_checksum(buf, length);
+
+	return length;
+}
+
+static inline int
+hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame, const void *buf,
+    size_t size)
+{
+	const uint8_t *p = buf;
+	int ret;
+
+	memset(frame, 0, sizeof(*frame));
+
+	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
+	if (ret)
+		return ret;
+	if (frame->header.length != HDMI_AVI_INFOFRAME_SIZE)
+		return -EINVAL;
+	p += HDMI_INFOFRAME_HEADER_SIZE;
+	size -= HDMI_INFOFRAME_HEADER_SIZE;
+
+	frame->colorspace = __SHIFTOUT(p[0], __BITS(6,5));
+	frame->scan_mode = __SHIFTOUT(p[0], __BITS(1,0));
+
+	frame->colorimetry = __SHIFTOUT(p[1], __BITS(7,6));
+	frame->picture_aspect = __SHIFTOUT(p[1], __BITS(5,4));
+	if (p[0] & __BIT(4))
+		frame->active_aspect = __SHIFTOUT(p[1], __BITS(3,0));
+
+	frame->itc = __SHIFTOUT(p[2], __BIT(7));
+	frame->extended_colorimetry = __SHIFTOUT(p[2], __BITS(6,4));
+	frame->quantization_range = __SHIFTOUT(p[2], __BITS(3,2));
+	frame->nups = __SHIFTOUT(p[2], __BITS(1,0));
+
+	frame->video_code = p[3];
+
+	frame->ycc_quantization_range = __SHIFTOUT(p[4], __BITS(7,6));
+	frame->content_type = __SHIFTOUT(p[4], __BITS(5,4));
+	frame->pixel_repeat = __SHIFTOUT(p[4], __BITS(3,0));
+
+	if (p[0] & __BIT(3)) {
+		frame->top_bar = le16dec(&p[5]);
+		frame->bottom_bar = le16dec(&p[7]);
+	}
+	if (p[0] & __BIT(2)) {
+		frame->left_bar = le16dec(&p[9]);
+		frame->right_bar = le16dec(&p[11]);
+	}
+
+	return 0;
+}
+
+#define	HDMI_DRM_INFOFRAME_SIZE		26
+struct hdmi_drm_infoframe {
+	struct hdmi_infoframe_header	header;
+	enum hdmi_eotf			eotf;
+	enum hdmi_metadata_type		metadata_type;
+	struct {
+		uint16_t	x, y;
+	}				display_primaries[3];
+	struct {
+		uint16_t	x, y;
+	}				white_point;
+	uint16_t			max_display_mastering_luminance;
+	uint16_t			min_display_mastering_luminance;
+	uint16_t			max_cll;
+	uint16_t			max_fall;
+};
+
+static inline int
+hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame)
+{
+	static const struct hdmi_drm_infoframe zero_frame;
+
+	*frame = zero_frame;
+
+	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_DRM,
+	    1, HDMI_DRM_INFOFRAME_SIZE);
+
+	return 0;
+}
+
+static inline int
+hdmi_drm_infoframe_check(const struct hdmi_drm_infoframe *frame)
+{
+	int ret;
+
+	ret = hdmi_infoframe_header_check(&frame->header,
+	    HDMI_INFOFRAME_TYPE_DRM, 1, HDMI_DRM_INFOFRAME_SIZE);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+#define	hdmi_drm_infoframe_pack_only	hdmi_drm_infoframe_pack /* XXX */
+
+static inline int
+hdmi_drm_infoframe_pack(const struct hdmi_drm_infoframe *frame,
+    void *buf, size_t size)
+{
+	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
+	    HDMI_DRM_INFOFRAME_SIZE;
+	uint8_t *p = buf;
+	unsigned i;
+	int ret;
+
+	KASSERT(frame->header.length == HDMI_DRM_INFOFRAME_SIZE);
+
+	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
+	if (ret < 0)
+		return ret;
+	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
+	p += HDMI_INFOFRAME_HEADER_SIZE;
+	size -= HDMI_INFOFRAME_HEADER_SIZE;
+
+	p[0] = frame->eotf;
+	p[1] = frame->metadata_type;
+	for (i = 0; i < __arraycount(frame->display_primaries); i++) {
+		le16enc(&p[2 + 4*i], frame->display_primaries[i].x);
+		le16enc(&p[2 + 4*i + 2], frame->display_primaries[i].y);
+	}
+	le16enc(&p[14], frame->white_point.x);
+	le16enc(&p[16], frame->white_point.y);
+	le16enc(&p[18], frame->min_display_mastering_luminance);
+	le16enc(&p[20], frame->max_display_mastering_luminance);
+	le16enc(&p[22], frame->max_cll);
+	le16enc(&p[24], frame->max_fall);
+	CTASSERT(HDMI_DRM_INFOFRAME_SIZE == 26);
+
+	hdmi_infoframe_set_checksum(buf, length);
 
 	return length;
 }
 
+static inline int
+hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe *frame, const void *buf,
+    size_t size)
+{
+	const uint8_t *p = buf;
+	unsigned i;
+	int ret;
+
+	memset(frame, 0, sizeof(*frame));
+
+	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
+	if (ret)
+		return ret;
+	if (frame->header.length != HDMI_DRM_INFOFRAME_SIZE)
+		return -EINVAL;
+	p += HDMI_INFOFRAME_HEADER_SIZE;
+	size -= HDMI_INFOFRAME_HEADER_SIZE;
+
+	frame->eotf = p[0];
+	frame->metadata_type = p[1];
+	for (i = 0; i < __arraycount(frame->display_primaries); i++) {
+		frame->display_primaries[i].x = le16dec(&p[2 + 4*i]);
+		frame->display_primaries[i].y = le16dec(&p[2 + 4*i + 2]);
+	}
+	frame->white_point.x = le16dec(&p[14]);
+	frame->white_point.y = le16dec(&p[16]);
+	frame->min_display_mastering_luminance = le16dec(&p[18]);
+	frame->max_display_mastering_luminance = le16dec(&p[20]);
+	frame->max_cll = le16dec(&p[22]);
+	frame->max_fall = le16dec(&p[24]);
+
+	return 0;
+}
+
 #define	HDMI_SPD_INFOFRAME_SIZE		25
 struct hdmi_spd_infoframe {
 	struct hdmi_infoframe_header	header;
@@ -463,8 +712,21 @@ hdmi_spd_infoframe_init(struct hdmi_spd_
 	return 0;
 }
 
+static inline int
+hdmi_spd_infoframe_check(const struct hdmi_spd_infoframe *frame)
+{
+	int ret;
+
+	ret = hdmi_infoframe_header_check(&frame->header,
+	    HDMI_INFOFRAME_TYPE_SPD, 2, HDMI_SPD_INFOFRAME_SIZE);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 static inline ssize_t
-hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buf,
+hdmi_spd_infoframe_pack(const struct hdmi_spd_infoframe *frame, void *buf,
     size_t size)
 {
 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
@@ -481,16 +743,40 @@ hdmi_spd_infoframe_pack(struct hdmi_spd_
 	p += HDMI_INFOFRAME_HEADER_SIZE;
 	size -= HDMI_INFOFRAME_HEADER_SIZE;
 
-	(void)memcpy(&p[0], frame->vendor, 8);
-	(void)memcpy(&p[8], frame->product, 16);
+	memcpy(&p[0], frame->vendor, 8);
+	memcpy(&p[8], frame->product, 16);
 	p[24] = frame->sdi;
 	CTASSERT(HDMI_SPD_INFOFRAME_SIZE == 25);
 
-	hdmi_infoframe_checksum(buf, length);
+	hdmi_infoframe_set_checksum(buf, length);
 
 	return length;
 }
 
+static inline int
+hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame, const void *buf,
+    size_t size)
+{
+	const uint8_t *p = buf;
+	int ret;
+
+	memset(frame, 0, sizeof(*frame));
+
+	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
+	if (ret)
+		return ret;
+	if (frame->header.length != HDMI_SPD_INFOFRAME_SIZE)
+		return -EINVAL;
+	p += HDMI_INFOFRAME_HEADER_SIZE;
+	size -= HDMI_INFOFRAME_HEADER_SIZE;
+
+	memcpy(frame->vendor, &p[0], 8);
+	memcpy(frame->product, &p[8], 8);
+	frame->sdi = p[24];
+
+	return 0;
+}
+
 #define	HDMI_IEEE_OUI		0x000c03
 #define	HDMI_FORUM_IEEE_OUI	0xc45dd8
 
@@ -526,6 +812,38 @@ hdmi_vendor_infoframe_init(struct hdmi_v
 	return 0;
 }
 
+static inline size_t
+hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame)
+{
+
+	if (frame->vic) {
+		return 5;
+	} else if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
+		if (frame->s3d_struct < HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
+			return 5;
+		else
+			return 6;
+	} else {
+		return 4;
+	}
+}
+
+static inline int
+hdmi_vendor_infoframe_check(const struct hdmi_vendor_infoframe *frame)
+{
+
+	if (frame->header.type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->header.version != 1)
+		return -EINVAL;
+	/* frame->header.length not used when packing */
+
+	/* At most one may be supplied.  */
+	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
 static inline int
 hdmi_vendor_infoframe_pack(const struct hdmi_vendor_infoframe *frame,
     void *buf, size_t size)
@@ -534,14 +852,12 @@ hdmi_vendor_infoframe_pack(const struct 
 	size_t length;
 	int ret;
 
-	/* Exactly one must be supplied.  */
-	if ((frame->vic == 0) ==
-	    (frame->s3d_struct == HDMI_3D_STRUCTURE_INVALID))
+	/* At most one may be supplied.  */
+	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
 		return -EINVAL;
 
-	length = HDMI_INFOFRAME_HEADER_SIZE + 6;
-	if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
-		length += 1;
+	length = HDMI_INFOFRAME_HEADER_SIZE;
+	length += hdmi_vendor_infoframe_length(frame);
 
 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
 	if (ret < 0)
@@ -554,89 +870,71 @@ hdmi_vendor_infoframe_pack(const struct 
 	p[1] = 0x0c;
 	p[2] = 0x00;
 
-	if (frame->vic == 0) {
+	if (frame->vic) {
+		p[3] = __SHIFTIN(0x1, __BITS(6,5));
+		p[4] = frame->vic;
+	} else if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
 		p[3] = __SHIFTIN(0x2, __BITS(6,5));
 		p[4] = __SHIFTIN(frame->s3d_struct, __BITS(7,4));
 		if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
 			p[5] = __SHIFTIN(frame->s3d_ext_data, __BITS(7,4));
 	} else {
-		p[3] = __SHIFTIN(0x1, __BITS(6,5));
-		p[4] = frame->vic;
+		p[3] = __SHIFTIN(0x0, __BITS(6,5));
 	}
 
-	hdmi_infoframe_checksum(buf, length);
+	hdmi_infoframe_set_checksum(buf, length);
 
 	return length;
 }
 
-#define	HDMI_DRM_INFOFRAME_SIZE		26
-struct hdmi_drm_infoframe {
-	struct hdmi_infoframe_header	header;
-	enum hdmi_eotf			eotf;
-	enum hdmi_metadata_type		metadata_type;
-	struct {
-		uint16_t	x, y;
-	}				display_primaries[3];
-	struct {
-		uint16_t	x, y;
-	}				white_point;
-	uint16_t			max_display_mastering_luminance;
-	uint16_t			min_display_mastering_luminance;
-	uint16_t			max_cll;
-	uint16_t			max_fall;
-};
-
-static inline int
-hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame)
-{
-	static const struct hdmi_drm_infoframe zero_frame;
-
-	*frame = zero_frame;
-
-	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_DRM,
-	    1, HDMI_DRM_INFOFRAME_SIZE);
-
-	return 0;
-}
-
-#define	hdmi_drm_infoframe_pack_only	hdmi_drm_infoframe_pack /* XXX */
-
 static inline int
-hdmi_drm_infoframe_pack(const struct hdmi_drm_infoframe *frame,
-    void *buf, size_t size)
+hdmi_vendor_infoframe_unpack(struct hdmi_vendor_infoframe *frame,
+    const void *buf, size_t size)
 {
-	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
-	    HDMI_DRM_INFOFRAME_SIZE;
-	uint8_t *p = buf;
-	unsigned i;
+	const uint8_t *p = buf;
 	int ret;
 
-	KASSERT(frame->header.length == HDMI_DRM_INFOFRAME_SIZE);
+	memset(frame, 0, sizeof(*frame));
 
-	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
-	if (ret < 0)
+	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
+	if (ret)
 		return ret;
-	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
+	if (frame->header.length < 4)
+		return -EINVAL;
 	p += HDMI_INFOFRAME_HEADER_SIZE;
 	size -= HDMI_INFOFRAME_HEADER_SIZE;
 
-	p[0] = frame->eotf;
-	p[1] = frame->metadata_type;
-	for (i = 0; i < __arraycount(frame->display_primaries); i++) {
-		le16enc(&p[2 + 4*i], frame->display_primaries[i].x);
-		le16enc(&p[2 + 4*i + 1], frame->display_primaries[i].y);
-	}
-	le16enc(&p[14], frame->white_point.x);
-	le16enc(&p[16], frame->white_point.y);
-	le16enc(&p[18], frame->min_display_mastering_luminance);
-	le16enc(&p[20], frame->max_display_mastering_luminance);
-	le16enc(&p[22], frame->max_cll);
-	le16enc(&p[24], frame->max_fall);
-	CTASSERT(HDMI_DRM_INFOFRAME_SIZE == 26);
+	if (p[0] != 0x03 || p[1] != 0x0c || p[2] != 0x00)
+		return -EINVAL;
 
-	hdmi_infoframe_checksum(buf, length);
+	switch (__SHIFTOUT(p[3], __BITS(6,5))) {
+	case 0x0:
+		if (frame->header.length != 4)
+			return -EINVAL;
+		break;
+	case 0x1:
+		if (frame->header.length != 5)
+			return -EINVAL;
+		frame->vic = p[4];
+		break;
+	case 0x2:
+		if (frame->header.length < 5)
+			return -EINVAL;
+		frame->s3d_struct = __SHIFTOUT(p[4], __BITS(7,4));
+		if (frame->s3d_struct < HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
+			if (frame->header.length != 5)
+				return -EINVAL;
+		} else {
+			if (frame->header.length != 6)
+				return -EINVAL;
+			frame->s3d_ext_data = __SHIFTOUT(p[5], __BITS(7,4));
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
 
-	return length;
+	return 0;
 }
 
 union hdmi_infoframe {
@@ -647,8 +945,10 @@ union hdmi_infoframe {
 	union hdmi_vendor_any_infoframe	vendor;
 };
 
+#define	hdmi_infoframe_pack_only	hdmi_infoframe_pack /* XXX */
+
 static inline ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buf, size_t size)
+hdmi_infoframe_pack(const union hdmi_infoframe *frame, void *buf, size_t size)
 {
 
 	switch (frame->any.type) {
@@ -666,6 +966,31 @@ hdmi_infoframe_pack(union hdmi_infoframe
 	}
 }
 
+static inline int
+hdmi_infoframe_unpack(union hdmi_infoframe *frame, const void *buf,
+    size_t size)
+{
+	struct hdmi_infoframe_header header;
+	int ret;
+
+	ret = hdmi_infoframe_header_unpack(&header, buf, size);
+	if (ret)
+		return ret;
+	switch (header.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		return hdmi_avi_infoframe_unpack(&frame->avi, buf, size);
+	case HDMI_INFOFRAME_TYPE_DRM:
+		return hdmi_drm_infoframe_unpack(&frame->drm, buf, size);
+	case HDMI_INFOFRAME_TYPE_SPD:
+		return hdmi_spd_infoframe_unpack(&frame->spd, buf, size);
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		return hdmi_vendor_infoframe_unpack(&frame->vendor.hdmi, buf,
+		    size);
+	default:
+		return -EINVAL;
+	}
+}
+
 static inline void
 hdmi_infoframe_log(const char *level, struct device *device,
     const union hdmi_infoframe *frame)

Reply via email to