Module Name:    src
Committed By:   riastradh
Date:           Sat Jul  9 17:59:28 UTC 2022

Modified Files:
        src/sys/external/bsd/drm2/include/linux: hdmi.h
        src/sys/external/bsd/drm2/linux: files.drmkms_linux
Added Files:
        src/sys/external/bsd/drm2/linux: linux_hdmi.c

Log Message:
linux/hdmi.h: Split out logic into .c file.

Shoulda done this ages ago.


To generate a diff of this commit:
cvs rdiff -u -r1.16 -r1.17 src/sys/external/bsd/drm2/include/linux/hdmi.h
cvs rdiff -u -r1.42 -r1.43 src/sys/external/bsd/drm2/linux/files.drmkms_linux
cvs rdiff -u -r0 -r1.1 src/sys/external/bsd/drm2/linux/linux_hdmi.c

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.16 src/sys/external/bsd/drm2/include/linux/hdmi.h:1.17
--- src/sys/external/bsd/drm2/include/linux/hdmi.h:1.16	Sat Jul  9 17:13:04 2022
+++ src/sys/external/bsd/drm2/include/linux/hdmi.h	Sat Jul  9 17:59:27 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: hdmi.h,v 1.16 2022/07/09 17:13:04 riastradh Exp $	*/
+/*	$NetBSD: hdmi.h,v 1.17 2022/07/09 17:59:27 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -33,11 +33,36 @@
 #define	_LINUX_HDMI_H_
 
 #include <sys/types.h>
-#include <sys/param.h>
-#include <sys/errno.h>
-#include <sys/systm.h>
 
-#include <lib/libkern/libkern.h>
+struct device;
+
+/* namespace */
+#define	hdmi_audio_infoframe_init	linux_hdmi_audio_infoframe_init
+#define	hdmi_audio_infoframe_pack	linux_hdmi_audio_infoframe_pack
+#define	hdmi_audio_infoframe_unpack	linux_hdmi_audio_infoframe_unpack
+#define	hdmi_avi_infoframe_check	linux_hdmi_avi_infoframe_check
+#define	hdmi_avi_infoframe_pack		linux_hdmi_avi_infoframe_pack
+#define	hdmi_avi_infoframe_unpack	linux_hdmi_avi_infoframe_unpack
+#define	hdmi_drm_infoframe_check	linux_hdmi_drm_infoframe_check
+#define	hdmi_drm_infoframe_init		linux_hdmi_drm_infoframe_init
+#define	hdmi_drm_infoframe_pack		linux_hdmi_drm_infoframe_pack
+#define	hdmi_drm_infoframe_pack_only	linux_hdmi_drm_infoframe_pack_only
+#define	hdmi_drm_infoframe_unpack	linux_hdmi_drm_infoframe_unpack
+#define	hdmi_infoframe_checksum		linux_hdmi_infoframe_checksum
+#define	hdmi_infoframe_log		linux_hdmi_infoframe_log
+#define	hdmi_infoframe_pack		linux_hdmi_infoframe_pack
+#define	hdmi_infoframe_pack_only	linux_hdmi_infoframe_pack_only
+#define	hdmi_infoframe_set_checksum	linux_hdmi_infoframe_set_checksum
+#define	hdmi_infoframe_unpack		linux_hdmi_infoframe_unpack
+#define	hdmi_spd_infoframe_check	linux_hdmi_spd_infoframe_check
+#define	hdmi_spd_infoframe_init		linux_hdmi_spd_infoframe_init
+#define	hdmi_spd_infoframe_pack		linux_hdmi_spd_infoframe_pack
+#define	hdmi_spd_infoframe_unpack	linux_hdmi_spd_infoframe_unpack
+#define	hdmi_vendor_infoframe_check	linux_hdmi_vendor_infoframe_check
+#define	hdmi_vendor_infoframe_init	linux_hdmi_vendor_infoframe_init
+#define	hdmi_vendor_infoframe_length	linux_hdmi_vendor_infoframe_length
+#define	hdmi_vendor_infoframe_pack	linux_hdmi_vendor_infoframe_pack
+#define	hdmi_vendor_infoframe_unpack	linux_hdmi_vendor_infoframe_unpack
 
 enum hdmi_3d_structure {
 	HDMI_3D_STRUCTURE_INVALID		= -1,
@@ -227,84 +252,6 @@ struct hdmi_infoframe_header {
 	/* checksum */
 };
 
-static inline void
-hdmi_infoframe_header_init(struct hdmi_infoframe_header *header,
-    enum hdmi_infoframe_type type, uint8_t vers, uint8_t length)
-{
-
-	header->type = type;
-	header->version = vers;
-	header->length = length;
-}
-
-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)
-{
-	uint8_t *const p = buf;
-
-	if (length < HDMI_INFOFRAME_HEADER_SIZE)
-		return -ENOSPC;
-	if (size < length)
-		return -ENOSPC;
-
-	p[0] = header->type;
-	p[1] = header->version;
-	p[2] = (length - HDMI_INFOFRAME_HEADER_SIZE);
-	p[3] = 0;		/* checksum */
-
-	return HDMI_INFOFRAME_HEADER_SIZE;
-}
-
-static inline uint8_t
-hdmi_infoframe_checksum(const void *buf, size_t length)
-{
-	const uint8_t *p = buf;
-	uint8_t checksum = 0;
-
-	while (length--)
-		checksum += *p++;
-
-	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
 struct hdmi_audio_infoframe {
 	struct hdmi_infoframe_header	header;
@@ -318,99 +265,6 @@ struct hdmi_audio_infoframe {
 	bool				downmix_inhibit;
 };
 
-static inline int
-hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
-{
-	static const struct hdmi_audio_infoframe zero_frame;
-
-	*frame = zero_frame;
-
-	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AUDIO,
-	    1, HDMI_AUDIO_INFOFRAME_SIZE);
-
-	return 0;
-}
-
-static inline ssize_t
-hdmi_audio_infoframe_pack(const struct hdmi_audio_infoframe *frame, void *buf,
-    size_t size)
-{
-	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
-	    HDMI_AUDIO_INFOFRAME_SIZE;
-	uint8_t channels = 0;
-	uint8_t *p = buf;
-	int ret;
-
-	KASSERT(frame->header.length == HDMI_AUDIO_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;
-
-	if (frame->channels >= 2)
-		channels = frame->channels - 1;
-
-	p[0] = __SHIFTIN(frame->coding_type, __BITS(7,4));
-	p[0] |= __SHIFTIN(channels, __BITS(2,0));
-
-	p[1] = __SHIFTIN(frame->sample_frequency, __BITS(4,2));
-	p[1] |= __SHIFTIN(frame->sample_size, __BITS(1,0));
-
-	p[2] = __SHIFTIN(frame->coding_type_ext, __BITS(5,0));
-
-	p[3] = __SHIFTIN(frame->level_shift_value, __BITS(6,3));
-
-	p[4] = __SHIFTIN(frame->downmix_inhibit? 1 : 0, __BIT(7));
-
-	/* PB6 to PB10 are reserved */
-	p[5] = 0;
-	p[6] = 0;
-	p[7] = 0;
-	p[8] = 0;
-	p[9] = 0;
-
-	CTASSERT(HDMI_AUDIO_INFOFRAME_SIZE == 10);
-
-	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;
@@ -433,130 +287,6 @@ struct hdmi_avi_infoframe {
 	uint16_t			right_bar;
 };
 
-static inline int
-hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
-{
-	static const struct hdmi_avi_infoframe zero_frame;
-
-	*frame = zero_frame;
-
-	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AVI, 2,
-	    HDMI_AVI_INFOFRAME_SIZE);
-
-	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)
-{
-	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
-	    HDMI_AVI_INFOFRAME_SIZE;
-	uint8_t *p = buf;
-	int ret;
-
-	KASSERT(frame->header.length == HDMI_AVI_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] = __SHIFTIN(frame->colorspace, __BITS(6,5));
-	p[0] |= __SHIFTIN(frame->active_aspect & 0xf? 1 : 0, __BIT(4));
-	p[0] |= __SHIFTIN(frame->top_bar || frame->bottom_bar, __BIT(3));
-	p[0] |= __SHIFTIN(frame->left_bar || frame->right_bar, __BIT(2));
-	p[0] |= __SHIFTIN(frame->scan_mode, __BITS(1,0));
-
-	p[1] = __SHIFTIN(frame->colorimetry, __BITS(7,6));
-	p[1] |= __SHIFTIN(frame->picture_aspect, __BITS(5,4));
-	p[1] |= __SHIFTIN(frame->active_aspect, __BITS(3,0));
-
-	p[2] = __SHIFTIN(frame->itc? 1 : 0, __BIT(7));
-	p[2] |= __SHIFTIN(frame->extended_colorimetry, __BITS(6,4));
-	p[2] |= __SHIFTIN(frame->quantization_range, __BITS(3,2));
-	p[2] |= __SHIFTIN(frame->nups, __BITS(1,0));
-
-	p[3] = frame->video_code;
-
-	p[4] = __SHIFTIN(frame->ycc_quantization_range, __BITS(7,6));
-	p[4] |= __SHIFTIN(frame->content_type, __BITS(5,4));
-	p[4] |= __SHIFTIN(frame->pixel_repeat, __BITS(3,0));
-
-	le16enc(&p[5], frame->top_bar);
-	le16enc(&p[7], frame->bottom_bar);
-	le16enc(&p[9], frame->left_bar);
-	le16enc(&p[11], frame->right_bar);
-	CTASSERT(HDMI_AVI_INFOFRAME_SIZE == 13);
-
-	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;
@@ -574,106 +304,6 @@ struct hdmi_drm_infoframe {
 	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;
@@ -697,88 +327,6 @@ struct hdmi_spd_infoframe {
 	}				sdi;
 };
 
-static inline int
-hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, const char *vendor,
-    const char *product)
-{
-	static const struct hdmi_spd_infoframe zero_frame;
-
-	*frame = zero_frame;
-
-	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_SPD,
-	    1, HDMI_SPD_INFOFRAME_SIZE);
-
-	strncpy(frame->vendor, vendor, sizeof(frame->vendor));
-	strncpy(frame->product, product, sizeof(frame->product));
-
-	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, 1, HDMI_SPD_INFOFRAME_SIZE);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static inline ssize_t
-hdmi_spd_infoframe_pack(const struct hdmi_spd_infoframe *frame, void *buf,
-    size_t size)
-{
-	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
-	    HDMI_SPD_INFOFRAME_SIZE;
-	uint8_t *p = buf;
-	int ret;
-
-	KASSERT(frame->header.length == HDMI_SPD_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;
-
-	memcpy(&p[0], frame->vendor, 8);
-	memcpy(&p[8], frame->product, 16);
-	p[24] = frame->sdi;
-	CTASSERT(HDMI_SPD_INFOFRAME_SIZE == 25);
-
-	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
 
@@ -798,147 +346,6 @@ union hdmi_vendor_any_infoframe {
 	struct hdmi_vendor_infoframe	hdmi;
 };
 
-static inline int
-hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
-{
-	static const struct hdmi_vendor_infoframe zero_frame;
-
-	*frame = zero_frame;
-
-	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_VENDOR,
-	    1, 0 /* depends on s3d_struct */);
-
-	frame->oui = HDMI_IEEE_OUI;
-	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
-
-	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)
-{
-	uint8_t *p = buf;
-	size_t length;
-	int ret;
-
-	/* At most one may be supplied.  */
-	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
-		return -EINVAL;
-
-	length = HDMI_INFOFRAME_HEADER_SIZE;
-	length += hdmi_vendor_infoframe_length(frame);
-
-	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] = 0x03;
-	p[1] = 0x0c;
-	p[2] = 0x00;
-
-	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(0x0, __BITS(6,5));
-	}
-
-	hdmi_infoframe_set_checksum(buf, length);
-
-	return length;
-}
-
-static inline int
-hdmi_vendor_infoframe_unpack(struct hdmi_vendor_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 < 4)
-		return -EINVAL;
-	p += HDMI_INFOFRAME_HEADER_SIZE;
-	size -= HDMI_INFOFRAME_HEADER_SIZE;
-
-	if (p[0] != 0x03 || p[1] != 0x0c || p[2] != 0x00)
-		return -EINVAL;
-
-	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 0;
-}
-
 union hdmi_infoframe {
 	struct hdmi_infoframe_header	any;
 	struct hdmi_avi_infoframe	avi;
@@ -947,58 +354,47 @@ 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(const union hdmi_infoframe *frame, void *buf, size_t size)
-{
-
-	switch (frame->any.type) {
-	case HDMI_INFOFRAME_TYPE_AVI:
-		return hdmi_avi_infoframe_pack(&frame->avi, buf, size);
-	case HDMI_INFOFRAME_TYPE_DRM:
-		return hdmi_drm_infoframe_pack(&frame->drm, buf, size);
-	case HDMI_INFOFRAME_TYPE_SPD:
-		return hdmi_spd_infoframe_pack(&frame->spd, buf, size);
-	case HDMI_INFOFRAME_TYPE_VENDOR:
-		return hdmi_vendor_infoframe_pack(&frame->vendor.hdmi, buf,
-		    size);
-	default:
-		return -EINVAL;
-	}
-}
-
-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)
-{
-
-	hexdump(printf, device_xname(device), frame, sizeof(*frame));
-}
+int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *);
+ssize_t hdmi_audio_infoframe_pack(const struct hdmi_audio_infoframe *, void *,
+    size_t);
+int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *, const void *,
+    size_t);
+
+int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *);
+int hdmi_avi_infoframe_check(const struct hdmi_avi_infoframe *);
+ssize_t hdmi_avi_infoframe_pack(const struct hdmi_avi_infoframe *, void *,
+    size_t);
+int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *, const void *,
+    size_t);
+
+int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *);
+int hdmi_drm_infoframe_check(const struct hdmi_drm_infoframe *);
+int hdmi_drm_infoframe_pack(const struct hdmi_drm_infoframe *, void *, size_t);
+int hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *, void *,
+    size_t);
+int hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe *, const void *,
+    size_t);
+
+int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *, const char *,
+    const char *);
+int hdmi_spd_infoframe_check(const struct hdmi_spd_infoframe *);
+ssize_t hdmi_spd_infoframe_pack(const struct hdmi_spd_infoframe *, void *,
+    size_t);
+int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *, const void *,
+    size_t);
+
+int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *);
+size_t hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *);
+int hdmi_vendor_infoframe_check(const struct hdmi_vendor_infoframe *);
+int hdmi_vendor_infoframe_pack(const struct hdmi_vendor_infoframe *, void *,
+    size_t);
+int hdmi_vendor_infoframe_unpack(struct hdmi_vendor_infoframe *, const void *,
+    size_t);
+
+ssize_t hdmi_infoframe_pack(const union hdmi_infoframe *, void *, size_t);
+ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *, void *, size_t);
+int hdmi_infoframe_unpack(union hdmi_infoframe *, const void *, size_t);
+void hdmi_infoframe_log(const char *, struct device *,
+    const union hdmi_infoframe *);
 
 #endif	/* _LINUX_HDMI_H_ */

Index: src/sys/external/bsd/drm2/linux/files.drmkms_linux
diff -u src/sys/external/bsd/drm2/linux/files.drmkms_linux:1.42 src/sys/external/bsd/drm2/linux/files.drmkms_linux:1.43
--- src/sys/external/bsd/drm2/linux/files.drmkms_linux:1.42	Sun Feb 27 15:02:58 2022
+++ src/sys/external/bsd/drm2/linux/files.drmkms_linux	Sat Jul  9 17:59:27 2022
@@ -1,4 +1,4 @@
-#       $NetBSD: files.drmkms_linux,v 1.42 2022/02/27 15:02:58 jakllsch Exp $
+#       $NetBSD: files.drmkms_linux,v 1.43 2022/07/09 17:59:27 riastradh Exp $
 
 define	drmkms_linux: i2cexec, i2c_bitbang
 
@@ -15,6 +15,7 @@ file	external/bsd/drm2/linux/linux_dma_f
 file	external/bsd/drm2/linux/linux_dma_resv.c	drmkms_linux
 file	external/bsd/drm2/linux/linux_dmi.c		drmkms_linux
 file	external/bsd/drm2/linux/linux_firmware.c	drmkms_linux
+file	external/bsd/drm2/linux/linux_hdmi.c		drmkms_linux
 file	external/bsd/drm2/linux/linux_hrtimer.c		drmkms_linux
 file	external/bsd/drm2/linux/linux_i2c.c		drmkms_linux
 file	external/bsd/drm2/linux/linux_idr.c		drmkms_linux

Added files:

Index: src/sys/external/bsd/drm2/linux/linux_hdmi.c
diff -u /dev/null src/sys/external/bsd/drm2/linux/linux_hdmi.c:1.1
--- /dev/null	Sat Jul  9 17:59:28 2022
+++ src/sys/external/bsd/drm2/linux/linux_hdmi.c	Sat Jul  9 17:59:27 2022
@@ -0,0 +1,729 @@
+/*	$NetBSD: linux_hdmi.c,v 1.1 2022/07/09 17:59:27 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: linux_hdmi.c,v 1.1 2022/07/09 17:59:27 riastradh Exp $");
+
+#include <sys/types.h>
+
+#include <sys/device.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+
+#include <lib/libkern/libkern.h>
+
+#include <linux/hdmi.h>
+
+/* Infoframe headers */
+
+static void
+hdmi_infoframe_header_init(struct hdmi_infoframe_header *header,
+    enum hdmi_infoframe_type type, uint8_t vers, uint8_t length)
+{
+
+	header->type = type;
+	header->version = vers;
+	header->length = length;
+}
+
+static 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 int
+hdmi_infoframe_header_pack(const struct hdmi_infoframe_header *header,
+    uint8_t length, void *buf, size_t size)
+{
+	uint8_t *const p = buf;
+
+	if (length < HDMI_INFOFRAME_HEADER_SIZE)
+		return -ENOSPC;
+	if (size < length)
+		return -ENOSPC;
+
+	p[0] = header->type;
+	p[1] = header->version;
+	p[2] = (length - HDMI_INFOFRAME_HEADER_SIZE);
+	p[3] = 0;		/* checksum */
+
+	return HDMI_INFOFRAME_HEADER_SIZE;
+}
+
+static uint8_t
+hdmi_infoframe_checksum(const void *buf, size_t length)
+{
+	const uint8_t *p = buf;
+	uint8_t checksum = 0;
+
+	while (length--)
+		checksum += *p++;
+
+	return 256 - checksum;
+}
+
+static 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 void
+hdmi_infoframe_set_checksum(void *buf, size_t length)
+{
+	uint8_t *p = buf;
+
+	p[3] = hdmi_infoframe_checksum(buf, length);
+}
+
+/* Audio infoframes */
+
+int
+hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
+{
+	static const struct hdmi_audio_infoframe zero_frame;
+
+	*frame = zero_frame;
+
+	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AUDIO,
+	    1, HDMI_AUDIO_INFOFRAME_SIZE);
+
+	return 0;
+}
+
+ssize_t
+hdmi_audio_infoframe_pack(const struct hdmi_audio_infoframe *frame, void *buf,
+    size_t size)
+{
+	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
+	    HDMI_AUDIO_INFOFRAME_SIZE;
+	uint8_t channels = 0;
+	uint8_t *p = buf;
+	int ret;
+
+	KASSERT(frame->header.length == HDMI_AUDIO_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;
+
+	if (frame->channels >= 2)
+		channels = frame->channels - 1;
+
+	p[0] = __SHIFTIN(frame->coding_type, __BITS(7,4));
+	p[0] |= __SHIFTIN(channels, __BITS(2,0));
+
+	p[1] = __SHIFTIN(frame->sample_frequency, __BITS(4,2));
+	p[1] |= __SHIFTIN(frame->sample_size, __BITS(1,0));
+
+	p[2] = __SHIFTIN(frame->coding_type_ext, __BITS(5,0));
+
+	p[3] = __SHIFTIN(frame->level_shift_value, __BITS(6,3));
+
+	p[4] = __SHIFTIN(frame->downmix_inhibit? 1 : 0, __BIT(7));
+
+	/* PB6 to PB10 are reserved */
+	p[5] = 0;
+	p[6] = 0;
+	p[7] = 0;
+	p[8] = 0;
+	p[9] = 0;
+
+	CTASSERT(HDMI_AUDIO_INFOFRAME_SIZE == 10);
+
+	hdmi_infoframe_set_checksum(buf, length);
+
+	return length;
+}
+
+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;
+}
+
+/* AVI infoframes */
+
+int
+hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
+{
+	static const struct hdmi_avi_infoframe zero_frame;
+
+	*frame = zero_frame;
+
+	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AVI, 2,
+	    HDMI_AVI_INFOFRAME_SIZE);
+
+	return 0;
+}
+
+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;
+}
+
+ssize_t
+hdmi_avi_infoframe_pack(const struct hdmi_avi_infoframe *frame, void *buf,
+    size_t size)
+{
+	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
+	    HDMI_AVI_INFOFRAME_SIZE;
+	uint8_t *p = buf;
+	int ret;
+
+	KASSERT(frame->header.length == HDMI_AVI_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] = __SHIFTIN(frame->colorspace, __BITS(6,5));
+	p[0] |= __SHIFTIN(frame->active_aspect & 0xf? 1 : 0, __BIT(4));
+	p[0] |= __SHIFTIN(frame->top_bar || frame->bottom_bar, __BIT(3));
+	p[0] |= __SHIFTIN(frame->left_bar || frame->right_bar, __BIT(2));
+	p[0] |= __SHIFTIN(frame->scan_mode, __BITS(1,0));
+
+	p[1] = __SHIFTIN(frame->colorimetry, __BITS(7,6));
+	p[1] |= __SHIFTIN(frame->picture_aspect, __BITS(5,4));
+	p[1] |= __SHIFTIN(frame->active_aspect, __BITS(3,0));
+
+	p[2] = __SHIFTIN(frame->itc? 1 : 0, __BIT(7));
+	p[2] |= __SHIFTIN(frame->extended_colorimetry, __BITS(6,4));
+	p[2] |= __SHIFTIN(frame->quantization_range, __BITS(3,2));
+	p[2] |= __SHIFTIN(frame->nups, __BITS(1,0));
+
+	p[3] = frame->video_code;
+
+	p[4] = __SHIFTIN(frame->ycc_quantization_range, __BITS(7,6));
+	p[4] |= __SHIFTIN(frame->content_type, __BITS(5,4));
+	p[4] |= __SHIFTIN(frame->pixel_repeat, __BITS(3,0));
+
+	le16enc(&p[5], frame->top_bar);
+	le16enc(&p[7], frame->bottom_bar);
+	le16enc(&p[9], frame->left_bar);
+	le16enc(&p[11], frame->right_bar);
+	CTASSERT(HDMI_AVI_INFOFRAME_SIZE == 13);
+
+	hdmi_infoframe_set_checksum(buf, length);
+
+	return length;
+}
+
+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;
+}
+
+/* DRM infoframes */
+
+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;
+}
+
+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;
+}
+
+__strong_alias(linux_hdmi_drm_infoframe_pack_only,linux_hdmi_drm_infoframe_pack) /* XXX */
+
+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;
+}
+
+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;
+}
+
+/* SPD infoframes */
+
+int
+hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, const char *vendor,
+    const char *product)
+{
+	static const struct hdmi_spd_infoframe zero_frame;
+
+	*frame = zero_frame;
+
+	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_SPD,
+	    1, HDMI_SPD_INFOFRAME_SIZE);
+
+	strncpy(frame->vendor, vendor, sizeof(frame->vendor));
+	strncpy(frame->product, product, sizeof(frame->product));
+
+	return 0;
+}
+
+int
+hdmi_spd_infoframe_check(const struct hdmi_spd_infoframe *frame)
+{
+	int ret;
+
+	ret = hdmi_infoframe_header_check(&frame->header,
+	    HDMI_INFOFRAME_TYPE_SPD, 1, HDMI_SPD_INFOFRAME_SIZE);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+ssize_t
+hdmi_spd_infoframe_pack(const struct hdmi_spd_infoframe *frame, void *buf,
+    size_t size)
+{
+	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
+	    HDMI_SPD_INFOFRAME_SIZE;
+	uint8_t *p = buf;
+	int ret;
+
+	KASSERT(frame->header.length == HDMI_SPD_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;
+
+	memcpy(&p[0], frame->vendor, 8);
+	memcpy(&p[8], frame->product, 16);
+	p[24] = frame->sdi;
+	CTASSERT(HDMI_SPD_INFOFRAME_SIZE == 25);
+
+	hdmi_infoframe_set_checksum(buf, length);
+
+	return length;
+}
+
+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;
+}
+
+/* Vendor infoframes */
+
+int
+hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
+{
+	static const struct hdmi_vendor_infoframe zero_frame;
+
+	*frame = zero_frame;
+
+	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_VENDOR,
+	    1, 0 /* depends on s3d_struct */);
+
+	frame->oui = HDMI_IEEE_OUI;
+	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
+
+	return 0;
+}
+
+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;
+	}
+}
+
+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;
+}
+
+int
+hdmi_vendor_infoframe_pack(const struct hdmi_vendor_infoframe *frame,
+    void *buf, size_t size)
+{
+	uint8_t *p = buf;
+	size_t length;
+	int ret;
+
+	/* At most one may be supplied.  */
+	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+		return -EINVAL;
+
+	length = HDMI_INFOFRAME_HEADER_SIZE;
+	length += hdmi_vendor_infoframe_length(frame);
+
+	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] = 0x03;
+	p[1] = 0x0c;
+	p[2] = 0x00;
+
+	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(0x0, __BITS(6,5));
+	}
+
+	hdmi_infoframe_set_checksum(buf, length);
+
+	return length;
+}
+
+int
+hdmi_vendor_infoframe_unpack(struct hdmi_vendor_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 < 4)
+		return -EINVAL;
+	p += HDMI_INFOFRAME_HEADER_SIZE;
+	size -= HDMI_INFOFRAME_HEADER_SIZE;
+
+	if (p[0] != 0x03 || p[1] != 0x0c || p[2] != 0x00)
+		return -EINVAL;
+
+	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 0;
+}
+
+/* union infoframe */
+
+__strong_alias(linux_hdmi_infoframe_pack_only,linux_hdmi_infoframe_pack) /* XXX */
+
+ssize_t
+hdmi_infoframe_pack(const union hdmi_infoframe *frame, void *buf, size_t size)
+{
+
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		return hdmi_avi_infoframe_pack(&frame->avi, buf, size);
+	case HDMI_INFOFRAME_TYPE_DRM:
+		return hdmi_drm_infoframe_pack(&frame->drm, buf, size);
+	case HDMI_INFOFRAME_TYPE_SPD:
+		return hdmi_spd_infoframe_pack(&frame->spd, buf, size);
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		return hdmi_vendor_infoframe_pack(&frame->vendor.hdmi, buf,
+		    size);
+	default:
+		return -EINVAL;
+	}
+}
+
+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;
+	}
+}
+
+void
+hdmi_infoframe_log(const char *level, struct device *device,
+    const union hdmi_infoframe *frame)
+{
+
+	hexdump(printf, device_xname(device), frame, sizeof(*frame));
+}

Reply via email to