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)