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));
+}