diff options
Diffstat (limited to 'drivers/video/hdmi.c')
| -rw-r--r-- | drivers/video/hdmi.c | 133 |
1 files changed, 74 insertions, 59 deletions
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index e70792b3e367..45b42f14a750 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -21,6 +21,7 @@ * DEALINGS IN THE SOFTWARE. */ +#include <drm/display/drm_dp.h> #include <linux/bitops.h> #include <linux/bug.h> #include <linux/errno.h> @@ -221,14 +222,18 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_pack); int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, const char *vendor, const char *product) { + size_t len; + memset(frame, 0, sizeof(*frame)); frame->type = HDMI_INFOFRAME_TYPE_SPD; frame->version = 1; frame->length = HDMI_SPD_INFOFRAME_SIZE; - strncpy(frame->vendor, vendor, sizeof(frame->vendor)); - strncpy(frame->product, product, sizeof(frame->product)); + len = strlen(vendor); + memcpy(frame->vendor, vendor, min(len, sizeof(frame->vendor))); + len = strlen(product); + memcpy(frame->product, product, min(len, sizeof(frame->product))); return 0; } @@ -377,12 +382,34 @@ static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *fr * * Returns 0 on success or a negative error code on failure. */ -int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame) +int hdmi_audio_infoframe_check(const struct hdmi_audio_infoframe *frame) { return hdmi_audio_infoframe_check_only(frame); } EXPORT_SYMBOL(hdmi_audio_infoframe_check); +static void +hdmi_audio_infoframe_pack_payload(const struct hdmi_audio_infoframe *frame, + u8 *buffer) +{ + u8 channels; + + if (frame->channels >= 2) + channels = frame->channels - 1; + else + channels = 0; + + buffer[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7); + buffer[1] = ((frame->sample_frequency & 0x7) << 2) | + (frame->sample_size & 0x3); + buffer[2] = frame->coding_type_ext & 0x1f; + buffer[3] = frame->channel_allocation; + buffer[4] = (frame->level_shift_value & 0xf) << 3; + + if (frame->downmix_inhibit) + buffer[4] |= BIT(7); +} + /** * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer * @frame: HDMI audio infoframe @@ -400,7 +427,6 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_check); 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; @@ -416,28 +442,13 @@ ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame, memset(buffer, 0, size); - if (frame->channels >= 2) - channels = frame->channels - 1; - else - channels = 0; - ptr[0] = frame->type; ptr[1] = frame->version; ptr[2] = frame->length; ptr[3] = 0; /* checksum */ - /* start infoframe payload */ - ptr += HDMI_INFOFRAME_HEADER_SIZE; - - ptr[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7); - ptr[1] = ((frame->sample_frequency & 0x7) << 2) | - (frame->sample_size & 0x3); - ptr[2] = frame->coding_type_ext & 0x1f; - ptr[3] = frame->channel_allocation; - ptr[4] = (frame->level_shift_value & 0xf) << 3; - - if (frame->downmix_inhibit) - ptr[4] |= BIT(7); + hdmi_audio_infoframe_pack_payload(frame, + ptr + HDMI_INFOFRAME_HEADER_SIZE); hdmi_infoframe_set_checksum(buffer, length); @@ -476,6 +487,43 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, EXPORT_SYMBOL(hdmi_audio_infoframe_pack); /** + * hdmi_audio_infoframe_pack_for_dp - Pack a HDMI Audio infoframe for DisplayPort + * + * @frame: HDMI Audio infoframe + * @sdp: Secondary data packet for DisplayPort. + * @dp_version: DisplayPort version to be encoded in the header + * + * Packs a HDMI Audio Infoframe to be sent over DisplayPort. This function + * fills the secondary data packet to be used for DisplayPort. + * + * Return: Number of total written bytes or a negative errno on failure. + */ +ssize_t +hdmi_audio_infoframe_pack_for_dp(const struct hdmi_audio_infoframe *frame, + struct dp_sdp *sdp, u8 dp_version) +{ + int ret; + + ret = hdmi_audio_infoframe_check(frame); + if (ret) + return ret; + + memset(sdp->db, 0, sizeof(sdp->db)); + + /* Secondary-data packet header */ + sdp->sdp_header.HB0 = 0; + sdp->sdp_header.HB1 = frame->type; + sdp->sdp_header.HB2 = DP_SDP_AUDIO_INFOFRAME_HB2; + sdp->sdp_header.HB3 = (dp_version & 0x3f) << 2; + + hdmi_audio_infoframe_pack_payload(frame, sdp->db); + + /* Return size = frame length + four HB for sdp_header */ + return frame->length + 4; +} +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_for_dp); + +/** * hdmi_vendor_infoframe_init() - initialize an HDMI vendor infoframe * @frame: HDMI vendor infoframe * @@ -495,7 +543,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame) * value */ frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID; - frame->length = 4; + frame->length = HDMI_VENDOR_INFOFRAME_SIZE; return 0; } @@ -847,34 +895,6 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame, } /** - * 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 @@ -1262,17 +1282,11 @@ static void hdmi_spd_infoframe_log(const char *level, struct device *dev, const struct hdmi_spd_infoframe *frame) { - u8 buf[17]; - hdmi_infoframe_log_header(level, dev, (const struct hdmi_any_infoframe *)frame); - memset(buf, 0, sizeof(buf)); - - strncpy(buf, frame->vendor, 8); - hdmi_log(" vendor: %s\n", buf); - strncpy(buf, frame->product, 16); - hdmi_log(" product: %s\n", buf); + hdmi_log(" vendor: %.8s\n", frame->vendor); + hdmi_log(" product: %.16s\n", frame->product); hdmi_log(" source device information: %s (0x%x)\n", hdmi_spd_sdi_get_name(frame->sdi), frame->sdi); } @@ -1688,7 +1702,8 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame, } /** - * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe + * hdmi_vendor_any_infoframe_unpack() - unpack binary buffer to a HDMI + * vendor infoframe * @frame: HDMI Vendor infoframe * @buffer: source buffer * @size: size of buffer |
