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)