diff options
author | Dave Airlie <airlied@redhat.com> | 2018-11-19 10:40:00 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2018-11-19 10:40:33 +1000 |
commit | d7563c55ef9fc1fd2301b8708b3c1f53509d6745 (patch) | |
tree | d7c8ba37972ecab71b056356366e136d5f2527ec /drivers/video | |
parent | 9ff01193a20d391e8dbce4403dd5ef87c7eaaca6 (diff) | |
parent | e7afb623b4fb82089c9a50c733c740522b8220bc (diff) |
Merge tag 'drm-misc-next-2018-11-07' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for v4.21, part 1:
UAPI Changes:
- Add syncobj timeline support to drm.
Cross-subsystem Changes:
- Remove shared fence staging in dma-buf's fence object, and allow
reserving more than 1 fence and add more paranoia when debugging.
- Constify infoframe functions in video/hdmi.
Core Changes:
- Add vkms todo, and a lot of assorted doc fixes.
- Drop transitional helpers and convert drivers to use drm_atomic_helper_shutdown().
- Move atomic state helper functions to drm_atomic_state_helper.[ch]
- Refactor drm selftests, and add new tests.
- DP MST atomic state cleanups.
- Drop EXPORT_SYMBOL from drm leases.
- Lease cleanups and fixes.
- Create render node for vgem.
Driver Changes:
- Fix build failure in imx without fbdev emulation.
- Add rotation quirk for GPD win2 panel.
- Add support for various CDTech panels, Banana Pi Panel, DLC1010GIG,
Olimex LCD-O-LinuXino, Samsung S6D16D0, Truly NT35597 WQXGA,
Himax HX8357D, simulated RTSM AEMv8.
- Add dw_hdmi support to rockchip driver.
- Fix YUV support in vc4.
- Fix resource id handling in virtio.
- Make rockchip use dw-mipi-dsi bridge driver, and add dual dsi support.
- Advertise that tinydrm only supports DRM_FORMAT_MOD_LINEAR.
- Convert many drivers to use atomic helpers, and drm_fbdev_generic_setup().
- Add Mali linear tiled formats, and enable them in the Mali-DP driver.
- Add support for H6 DE3 mixer 0, DW HDMI, HDMI PHY and TCON TOP.
- Assorted driver cleanups and fixes.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/be7ebd91-edd9-8fa4-4286-1c57e3165113@linux.intel.com
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/hdmi.c | 511 |
1 files changed, 454 insertions, 57 deletions
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index 8a3e8f61b991..799ae49774f5 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -31,7 +31,7 @@ #define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__) -static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size) +static u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size) { u8 csum = 0; size_t i; @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame) } EXPORT_SYMBOL(hdmi_avi_infoframe_init); +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame) +{ + if (frame->type != HDMI_INFOFRAME_TYPE_AVI || + frame->version != 2 || + frame->length != HDMI_AVI_INFOFRAME_SIZE) + return -EINVAL; + + if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9) + return -EINVAL; + + return 0; +} + /** - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer + * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe + * @frame: HDMI AVI infoframe + * + * Validates that the infoframe is consistent and updates derived fields + * (eg. length) based on other fields. + * + * Returns 0 on success or a negative error code on failure. + */ +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame) +{ + return hdmi_avi_infoframe_check_only(frame); +} +EXPORT_SYMBOL(hdmi_avi_infoframe_check); + +/** + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer * @frame: HDMI AVI infoframe * @buffer: destination buffer * @size: size of buffer @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init); * Returns the number of bytes packed into the binary buffer or a negative * error code on failure. */ -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, - size_t size) +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame, + void *buffer, size_t size) { u8 *ptr = buffer; size_t length; + int ret; + + ret = hdmi_avi_infoframe_check_only(frame); + if (ret) + return ret; length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; if (size < length) return -ENOSPC; - if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9) - return -EINVAL; - memset(buffer, 0, size); ptr[0] = frame->type; @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, return length; } +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only); + +/** + * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe, + * and write it to binary buffer + * @frame: HDMI AVI infoframe + * @buffer: destination buffer + * @size: size of buffer + * + * Validates that the infoframe is consistent and updates derived fields + * (eg. length) based on other fields, after which it packs the information + * contained in the @frame structure into a binary representation that + * can be written into the corresponding controller registers. This function + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4 + * specification. + * + * Returns the number of bytes packed into the binary buffer or a negative + * error code on failure. + */ +ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, + void *buffer, size_t size) +{ + int ret; + + ret = hdmi_avi_infoframe_check(frame); + if (ret) + return ret; + + return hdmi_avi_infoframe_pack_only(frame, buffer, size); +} EXPORT_SYMBOL(hdmi_avi_infoframe_pack); /** @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, } EXPORT_SYMBOL(hdmi_spd_infoframe_init); +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame) +{ + if (frame->type != HDMI_INFOFRAME_TYPE_SPD || + frame->version != 1 || + frame->length != HDMI_SPD_INFOFRAME_SIZE) + return -EINVAL; + + return 0; +} + /** - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer + * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe + * @frame: HDMI SPD infoframe + * + * Validates that the infoframe is consistent and updates derived fields + * (eg. length) based on other fields. + * + * Returns 0 on success or a negative error code on failure. + */ +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame) +{ + return hdmi_spd_infoframe_check_only(frame); +} +EXPORT_SYMBOL(hdmi_spd_infoframe_check); + +/** + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer * @frame: HDMI SPD infoframe * @buffer: destination buffer * @size: size of buffer @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init); * Returns the number of bytes packed into the binary buffer or a negative * error code on failure. */ -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer, - size_t size) +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame, + void *buffer, size_t size) { u8 *ptr = buffer; size_t length; + int ret; + + ret = hdmi_spd_infoframe_check_only(frame); + if (ret) + return ret; length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer, return length; } +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only); + +/** + * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe, + * and write it to binary buffer + * @frame: HDMI SPD infoframe + * @buffer: destination buffer + * @size: size of buffer + * + * Validates that the infoframe is consistent and updates derived fields + * (eg. length) based on other fields, after which it packs the information + * contained in the @frame structure into a binary representation that + * can be written into the corresponding controller registers. This function + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4 + * specification. + * + * Returns the number of bytes packed into the binary buffer or a negative + * error code on failure. + */ +ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, + void *buffer, size_t size) +{ + int ret; + + ret = hdmi_spd_infoframe_check(frame); + if (ret) + return ret; + + return hdmi_spd_infoframe_pack_only(frame, buffer, size); +} EXPORT_SYMBOL(hdmi_spd_infoframe_pack); /** @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame) } EXPORT_SYMBOL(hdmi_audio_infoframe_init); +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame) +{ + if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO || + frame->version != 1 || + frame->length != HDMI_AUDIO_INFOFRAME_SIZE) + return -EINVAL; + + return 0; +} + /** - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer + * hdmi_audio_infoframe_check() - check a HDMI audio infoframe + * @frame: HDMI audio infoframe + * + * Validates that the infoframe is consistent and updates derived fields + * (eg. length) based on other fields. + * + * Returns 0 on success or a negative error code on failure. + */ +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame) +{ + return hdmi_audio_infoframe_check_only(frame); +} +EXPORT_SYMBOL(hdmi_audio_infoframe_check); + +/** + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer * @frame: HDMI audio infoframe * @buffer: destination buffer * @size: size of buffer @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init); * Returns the number of bytes packed into the binary buffer or a negative * error code on failure. */ -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, - void *buffer, size_t size) +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame, + void *buffer, size_t size) { unsigned char channels; u8 *ptr = buffer; size_t length; + int ret; + + ret = hdmi_audio_infoframe_check_only(frame); + if (ret) + return ret; length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, return length; } +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only); + +/** + * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe, + * and write it to binary buffer + * @frame: HDMI Audio infoframe + * @buffer: destination buffer + * @size: size of buffer + * + * Validates that the infoframe is consistent and updates derived fields + * (eg. length) based on other fields, after which it packs the information + * contained in the @frame structure into a binary representation that + * can be written into the corresponding controller registers. This function + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4 + * specification. + * + * Returns the number of bytes packed into the binary buffer or a negative + * error code on failure. + */ +ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, + void *buffer, size_t size) +{ + int ret; + + ret = hdmi_audio_infoframe_check(frame); + if (ret) + return ret; + + return hdmi_audio_infoframe_pack_only(frame, buffer, size); +} EXPORT_SYMBOL(hdmi_audio_infoframe_pack); /** @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame) * value */ frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID; + frame->length = 4; return 0; } @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram return 4; } +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame) +{ + if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR || + frame->version != 1 || + frame->oui != HDMI_IEEE_OUI) + return -EINVAL; + + /* only one of those can be supplied */ + if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) + return -EINVAL; + + if (frame->length != hdmi_vendor_infoframe_length(frame)) + return -EINVAL; + + return 0; +} + +/** + * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe + * @frame: HDMI infoframe + * + * Validates that the infoframe is consistent and updates derived fields + * (eg. length) based on other fields. + * + * Returns 0 on success or a negative error code on failure. + */ +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame) +{ + frame->length = hdmi_vendor_infoframe_length(frame); + + return hdmi_vendor_infoframe_check_only(frame); +} +EXPORT_SYMBOL(hdmi_vendor_infoframe_check); + /** - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer * @frame: HDMI infoframe * @buffer: destination buffer * @size: size of buffer @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram * Returns the number of bytes packed into the binary buffer or a negative * error code on failure. */ -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, - void *buffer, size_t size) +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame, + void *buffer, size_t size) { u8 *ptr = buffer; size_t length; + int ret; - /* only one of those can be supplied */ - if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) - return -EINVAL; - - frame->length = hdmi_vendor_infoframe_length(frame); + ret = hdmi_vendor_infoframe_check_only(frame); + if (ret) + return ret; length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, return length; } +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only); + +/** + * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe, + * and write it to binary buffer + * @frame: HDMI Vendor infoframe + * @buffer: destination buffer + * @size: size of buffer + * + * Validates that the infoframe is consistent and updates derived fields + * (eg. length) based on other fields, after which it packs the information + * contained in the @frame structure into a binary representation that + * can be written into the corresponding controller registers. This function + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4 + * specification. + * + * Returns the number of bytes packed into the binary buffer or a negative + * error code on failure. + */ +ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, + void *buffer, size_t size) +{ + int ret; + + ret = hdmi_vendor_infoframe_check(frame); + if (ret) + return ret; + + return hdmi_vendor_infoframe_pack_only(frame, buffer, size); +} EXPORT_SYMBOL(hdmi_vendor_infoframe_pack); +static int +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame) +{ + if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR || + frame->any.version != 1) + return -EINVAL; + + return 0; +} + +/* + * hdmi_vendor_any_infoframe_check() - check a vendor infoframe + */ +static int +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame) +{ + int ret; + + ret = hdmi_vendor_any_infoframe_check_only(frame); + if (ret) + return ret; + + /* we only know about HDMI vendor infoframes */ + if (frame->any.oui != HDMI_IEEE_OUI) + return -EINVAL; + + return hdmi_vendor_infoframe_check(&frame->hdmi); +} + /* - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer */ static ssize_t -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame, - void *buffer, size_t size) +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame, + void *buffer, size_t size) { + int ret; + + ret = hdmi_vendor_any_infoframe_check_only(frame); + if (ret) + return ret; + /* we only know about HDMI vendor infoframes */ if (frame->any.oui != HDMI_IEEE_OUI) return -EINVAL; - return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size); + return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size); +} + +/* + * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe, + * and write it to binary buffer + */ +static ssize_t +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame, + void *buffer, size_t size) +{ + int ret; + + ret = hdmi_vendor_any_infoframe_check(frame); + if (ret) + return ret; + + return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size); } /** - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer + * hdmi_infoframe_check() - check a HDMI infoframe + * @frame: HDMI infoframe + * + * Validates that the infoframe is consistent and updates derived fields + * (eg. length) based on other fields. + * + * Returns 0 on success or a negative error code on failure. + */ +int +hdmi_infoframe_check(union hdmi_infoframe *frame) +{ + switch (frame->any.type) { + case HDMI_INFOFRAME_TYPE_AVI: + return hdmi_avi_infoframe_check(&frame->avi); + case HDMI_INFOFRAME_TYPE_SPD: + return hdmi_spd_infoframe_check(&frame->spd); + case HDMI_INFOFRAME_TYPE_AUDIO: + return hdmi_audio_infoframe_check(&frame->audio); + case HDMI_INFOFRAME_TYPE_VENDOR: + return hdmi_vendor_any_infoframe_check(&frame->vendor); + default: + WARN(1, "Bad infoframe type %d\n", frame->any.type); + return -EINVAL; + } +} +EXPORT_SYMBOL(hdmi_infoframe_check); + +/** + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer * @frame: HDMI infoframe * @buffer: destination buffer * @size: size of buffer @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame, * error code on failure. */ ssize_t -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size) +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size) +{ + ssize_t length; + + switch (frame->any.type) { + case HDMI_INFOFRAME_TYPE_AVI: + length = hdmi_avi_infoframe_pack_only(&frame->avi, + buffer, size); + break; + case HDMI_INFOFRAME_TYPE_SPD: + length = hdmi_spd_infoframe_pack_only(&frame->spd, + buffer, size); + break; + case HDMI_INFOFRAME_TYPE_AUDIO: + length = hdmi_audio_infoframe_pack_only(&frame->audio, + buffer, size); + break; + case HDMI_INFOFRAME_TYPE_VENDOR: + length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor, + buffer, size); + break; + default: + WARN(1, "Bad infoframe type %d\n", frame->any.type); + length = -EINVAL; + } + + return length; +} +EXPORT_SYMBOL(hdmi_infoframe_pack_only); + +/** + * hdmi_infoframe_pack() - check a HDMI infoframe, + * and write it to binary buffer + * @frame: HDMI infoframe + * @buffer: destination buffer + * @size: size of buffer + * + * Validates that the infoframe is consistent and updates derived fields + * (eg. length) based on other fields, after which it packs the information + * contained in the @frame structure into a binary representation that + * can be written into the corresponding controller registers. This function + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4 + * specification. + * + * Returns the number of bytes packed into the binary buffer or a negative + * error code on failure. + */ +ssize_t +hdmi_infoframe_pack(union hdmi_infoframe *frame, + void *buffer, size_t size) { ssize_t length; @@ -471,7 +844,7 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type) static void hdmi_infoframe_log_header(const char *level, struct device *dev, - struct hdmi_any_infoframe *frame) + const struct hdmi_any_infoframe *frame) { hdmi_log("HDMI infoframe: %s, version %u, length %u\n", hdmi_infoframe_type_get_name(frame->type), @@ -673,10 +1046,10 @@ hdmi_content_type_get_name(enum hdmi_content_type content_type) */ static void hdmi_avi_infoframe_log(const char *level, struct device *dev, - struct hdmi_avi_infoframe *frame) + const struct hdmi_avi_infoframe *frame) { hdmi_infoframe_log_header(level, dev, - (struct hdmi_any_infoframe *)frame); + (const struct hdmi_any_infoframe *)frame); hdmi_log(" colorspace: %s\n", hdmi_colorspace_get_name(frame->colorspace)); @@ -750,12 +1123,12 @@ static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi) */ static void hdmi_spd_infoframe_log(const char *level, struct device *dev, - struct hdmi_spd_infoframe *frame) + const struct hdmi_spd_infoframe *frame) { u8 buf[17]; hdmi_infoframe_log_header(level, dev, - (struct hdmi_any_infoframe *)frame); + (const struct hdmi_any_infoframe *)frame); memset(buf, 0, sizeof(buf)); @@ -886,10 +1259,10 @@ hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx) */ static void hdmi_audio_infoframe_log(const char *level, struct device *dev, - struct hdmi_audio_infoframe *frame) + const struct hdmi_audio_infoframe *frame) { hdmi_infoframe_log_header(level, dev, - (struct hdmi_any_infoframe *)frame); + (const struct hdmi_any_infoframe *)frame); if (frame->channels) hdmi_log(" channels: %u\n", frame->channels - 1); @@ -949,12 +1322,12 @@ hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct) static void hdmi_vendor_any_infoframe_log(const char *level, struct device *dev, - union hdmi_vendor_any_infoframe *frame) + const union hdmi_vendor_any_infoframe *frame) { - struct hdmi_vendor_infoframe *hvf = &frame->hdmi; + const struct hdmi_vendor_infoframe *hvf = &frame->hdmi; hdmi_infoframe_log_header(level, dev, - (struct hdmi_any_infoframe *)frame); + (const struct hdmi_any_infoframe *)frame); if (frame->any.oui != HDMI_IEEE_OUI) { hdmi_log(" not a HDMI vendor infoframe\n"); @@ -984,7 +1357,7 @@ hdmi_vendor_any_infoframe_log(const char *level, */ void hdmi_infoframe_log(const char *level, struct device *dev, - union hdmi_infoframe *frame) + const union hdmi_infoframe *frame) { switch (frame->any.type) { case HDMI_INFOFRAME_TYPE_AVI: @@ -1005,8 +1378,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log); /** * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe - * @buffer: source buffer * @frame: HDMI AVI infoframe + * @buffer: source buffer + * @size: size of buffer * * Unpacks the information contained in binary @buffer into a structured * @frame of the HDMI Auxiliary Video (AVI) information frame. @@ -1016,11 +1390,14 @@ EXPORT_SYMBOL(hdmi_infoframe_log); * Returns 0 on success or a negative error code on failure. */ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame, - void *buffer) + const void *buffer, size_t size) { - u8 *ptr = buffer; + const u8 *ptr = buffer; int ret; + if (size < HDMI_INFOFRAME_SIZE(AVI)) + return -EINVAL; + if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI || ptr[1] != 2 || ptr[2] != HDMI_AVI_INFOFRAME_SIZE) @@ -1068,8 +1445,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame, /** * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe - * @buffer: source buffer * @frame: HDMI SPD infoframe + * @buffer: source buffer + * @size: size of buffer * * Unpacks the information contained in binary @buffer into a structured * @frame of the HDMI Source Product Description (SPD) information frame. @@ -1079,11 +1457,14 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame, * Returns 0 on success or a negative error code on failure. */ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame, - void *buffer) + const void *buffer, size_t size) { - u8 *ptr = buffer; + const u8 *ptr = buffer; int ret; + if (size < HDMI_INFOFRAME_SIZE(SPD)) + return -EINVAL; + if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD || ptr[1] != 1 || ptr[2] != HDMI_SPD_INFOFRAME_SIZE) { @@ -1106,8 +1487,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame, /** * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe - * @buffer: source buffer * @frame: HDMI Audio infoframe + * @buffer: source buffer + * @size: size of buffer * * Unpacks the information contained in binary @buffer into a structured * @frame of the HDMI Audio information frame. @@ -1117,11 +1499,14 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame, * Returns 0 on success or a negative error code on failure. */ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame, - void *buffer) + const void *buffer, size_t size) { - u8 *ptr = buffer; + const u8 *ptr = buffer; int ret; + if (size < HDMI_INFOFRAME_SIZE(AUDIO)) + return -EINVAL; + if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO || ptr[1] != 1 || ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) { @@ -1151,8 +1536,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame, /** * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe - * @buffer: source buffer * @frame: HDMI Vendor infoframe + * @buffer: source buffer + * @size: size of buffer * * Unpacks the information contained in binary @buffer into a structured * @frame of the HDMI Vendor information frame. @@ -1163,14 +1549,17 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame, */ static int hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame, - void *buffer) + const void *buffer, size_t size) { - u8 *ptr = buffer; + const u8 *ptr = buffer; size_t length; int ret; u8 hdmi_video_format; struct hdmi_vendor_infoframe *hvf = &frame->hdmi; + if (size < HDMI_INFOFRAME_HEADER_SIZE) + return -EINVAL; + if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR || ptr[1] != 1 || (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6)) @@ -1178,6 +1567,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame, length = ptr[2]; + if (size < HDMI_INFOFRAME_HEADER_SIZE + length) + return -EINVAL; + if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_HEADER_SIZE + length) != 0) return -EINVAL; @@ -1224,8 +1616,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame, /** * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe - * @buffer: source buffer * @frame: HDMI infoframe + * @buffer: source buffer + * @size: size of buffer * * Unpacks the information contained in binary buffer @buffer into a structured * @frame of a HDMI infoframe. @@ -1234,23 +1627,27 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame, * * Returns 0 on success or a negative error code on failure. */ -int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer) +int hdmi_infoframe_unpack(union hdmi_infoframe *frame, + const void *buffer, size_t size) { int ret; - u8 *ptr = buffer; + const u8 *ptr = buffer; + + if (size < HDMI_INFOFRAME_HEADER_SIZE) + return -EINVAL; switch (ptr[0]) { case HDMI_INFOFRAME_TYPE_AVI: - ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer); + ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size); break; case HDMI_INFOFRAME_TYPE_SPD: - ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer); + ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size); break; case HDMI_INFOFRAME_TYPE_AUDIO: - ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer); + ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size); break; case HDMI_INFOFRAME_TYPE_VENDOR: - ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer); + ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size); break; default: ret = -EINVAL; |