diff options
Diffstat (limited to 'drivers/video/hdmi.c')
| -rw-r--r-- | drivers/video/hdmi.c | 88 |
1 files changed, 79 insertions, 9 deletions
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index 635d5690dd5..9e758a8f890 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -96,13 +96,18 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, ptr[0] = ((frame->colorspace & 0x3) << 5) | (frame->scan_mode & 0x3); - if (frame->active_info_valid) + /* + * Data byte 1, bit 4 has to be set if we provide the active format + * aspect ratio + */ + if (frame->active_aspect & 0xf) ptr[0] |= BIT(4); - if (frame->horizontal_bar_valid) + /* Bit 3 and 2 indicate if we transmit horizontal/vertical bar data */ + if (frame->top_bar || frame->bottom_bar) ptr[0] |= BIT(3); - if (frame->vertical_bar_valid) + if (frame->left_bar || frame->right_bar) ptr[0] |= BIT(2); ptr[1] = ((frame->colorimetry & 0x3) << 6) | @@ -283,9 +288,33 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, EXPORT_SYMBOL(hdmi_audio_infoframe_pack); /** - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary - * buffer + * hdmi_vendor_infoframe_init() - initialize an HDMI vendor infoframe * @frame: HDMI vendor infoframe + * + * Returns 0 on success or a negative error code on failure. + */ +int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame) +{ + memset(frame, 0, sizeof(*frame)); + + frame->type = HDMI_INFOFRAME_TYPE_VENDOR; + frame->version = 1; + + frame->oui = HDMI_IEEE_OUI; + + /* + * 0 is a valid value for s3d_struct, so we use a special "not set" + * value + */ + frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID; + + return 0; +} +EXPORT_SYMBOL(hdmi_vendor_infoframe_init); + +/** + * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer + * @frame: HDMI infoframe * @buffer: destination buffer * @size: size of buffer * @@ -298,11 +327,25 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_pack); * error code on failure. */ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, - void *buffer, size_t size) + void *buffer, size_t size) { u8 *ptr = buffer; size_t length; + /* empty info frame */ + if (frame->vic == 0 && frame->s3d_struct == HDMI_3D_STRUCTURE_INVALID) + return -EINVAL; + + /* only one of those can be supplied */ + if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) + return -EINVAL; + + /* for side by side (half) we also need to provide 3D_Ext_Data */ + if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) + frame->length = 6; + else + frame->length = 5; + length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; if (size < length) @@ -315,7 +358,20 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, ptr[2] = frame->length; ptr[3] = 0; /* checksum */ - memcpy(&ptr[HDMI_INFOFRAME_HEADER_SIZE], frame->data, frame->length); + /* HDMI OUI */ + ptr[4] = 0x03; + ptr[5] = 0x0c; + ptr[6] = 0x00; + + if (frame->vic) { + ptr[7] = 0x1 << 5; /* video format */ + ptr[8] = frame->vic; + } else { + ptr[7] = 0x2 << 5; /* video format */ + ptr[8] = (frame->s3d_struct & 0xf) << 4; + if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) + ptr[9] = (frame->s3d_ext_data & 0xf) << 4; + } hdmi_infoframe_checksum(buffer, length); @@ -323,6 +379,20 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, } EXPORT_SYMBOL(hdmi_vendor_infoframe_pack); +/* + * hdmi_vendor_any_infoframe_pack() - 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) +{ + /* 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); +} + /** * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer * @frame: HDMI infoframe @@ -353,8 +423,8 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size) length = hdmi_audio_infoframe_pack(&frame->audio, buffer, size); break; case HDMI_INFOFRAME_TYPE_VENDOR: - length = hdmi_vendor_infoframe_pack(&frame->vendor, - buffer, size); + length = hdmi_vendor_any_infoframe_pack(&frame->vendor, + buffer, size); break; default: WARN(1, "Bad infoframe type %d\n", frame->any.type); |
