-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
video: Add generic HDMI infoframe helpers
Add generic helpers to pack HDMI infoframes into binary buffers. Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de> Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
- Loading branch information
Thierry Reding
committed
Feb 22, 2013
1 parent
595887e
commit f142d3b
Showing
4 changed files
with
543 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,308 @@ | ||
/* | ||
* Copyright (C) 2012 Avionic Design GmbH | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <linux/bitops.h> | ||
#include <linux/errno.h> | ||
#include <linux/export.h> | ||
#include <linux/hdmi.h> | ||
#include <linux/string.h> | ||
|
||
static void hdmi_infoframe_checksum(void *buffer, size_t size) | ||
{ | ||
u8 *ptr = buffer; | ||
u8 csum = 0; | ||
size_t i; | ||
|
||
/* compute checksum */ | ||
for (i = 0; i < size; i++) | ||
csum += ptr[i]; | ||
|
||
ptr[3] = 256 - csum; | ||
} | ||
|
||
/** | ||
* hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe | ||
* @frame: HDMI AVI infoframe | ||
* | ||
* Returns 0 on success or a negative error code on failure. | ||
*/ | ||
int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame) | ||
{ | ||
memset(frame, 0, sizeof(*frame)); | ||
|
||
frame->type = HDMI_INFOFRAME_TYPE_AVI; | ||
frame->version = 2; | ||
frame->length = 13; | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL(hdmi_avi_infoframe_init); | ||
|
||
/** | ||
* hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer | ||
* @frame: HDMI AVI infoframe | ||
* @buffer: destination buffer | ||
* @size: size of buffer | ||
* | ||
* Packs the information contained in the @frame structure into a binary | ||
* representation that can be written into the corresponding controller | ||
* registers. 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) | ||
{ | ||
u8 *ptr = buffer; | ||
size_t length; | ||
|
||
length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; | ||
|
||
if (size < length) | ||
return -ENOSPC; | ||
|
||
memset(buffer, 0, length); | ||
|
||
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->colorspace & 0x3) << 5) | (frame->scan_mode & 0x3); | ||
|
||
if (frame->active_info_valid) | ||
ptr[0] |= BIT(4); | ||
|
||
if (frame->horizontal_bar_valid) | ||
ptr[0] |= BIT(3); | ||
|
||
if (frame->vertical_bar_valid) | ||
ptr[0] |= BIT(2); | ||
|
||
ptr[1] = ((frame->colorimetry & 0x3) << 6) | | ||
((frame->picture_aspect & 0x3) << 4) | | ||
(frame->active_aspect & 0xf); | ||
|
||
ptr[2] = ((frame->extended_colorimetry & 0x7) << 4) | | ||
((frame->quantization_range & 0x3) << 2) | | ||
(frame->nups & 0x3); | ||
|
||
if (frame->itc) | ||
ptr[2] |= BIT(7); | ||
|
||
ptr[3] = frame->video_code & 0x7f; | ||
|
||
ptr[4] = ((frame->ycc_quantization_range & 0x3) << 6) | | ||
((frame->content_type & 0x3) << 4) | | ||
(frame->pixel_repeat & 0xf); | ||
|
||
ptr[5] = frame->top_bar & 0xff; | ||
ptr[6] = (frame->top_bar >> 8) & 0xff; | ||
ptr[7] = frame->bottom_bar & 0xff; | ||
ptr[8] = (frame->bottom_bar >> 8) & 0xff; | ||
ptr[9] = frame->left_bar & 0xff; | ||
ptr[10] = (frame->left_bar >> 8) & 0xff; | ||
ptr[11] = frame->right_bar & 0xff; | ||
ptr[12] = (frame->right_bar >> 8) & 0xff; | ||
|
||
hdmi_infoframe_checksum(buffer, length); | ||
|
||
return length; | ||
} | ||
EXPORT_SYMBOL(hdmi_avi_infoframe_pack); | ||
|
||
/** | ||
* hdmi_spd_infoframe_init() - initialize an HDMI SPD infoframe | ||
* @frame: HDMI SPD infoframe | ||
* @vendor: vendor string | ||
* @product: product string | ||
* | ||
* Returns 0 on success or a negative error code on failure. | ||
*/ | ||
int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, | ||
const char *vendor, const char *product) | ||
{ | ||
memset(frame, 0, sizeof(*frame)); | ||
|
||
frame->type = HDMI_INFOFRAME_TYPE_SPD; | ||
frame->version = 1; | ||
frame->length = 25; | ||
|
||
strncpy(frame->vendor, vendor, sizeof(frame->vendor)); | ||
strncpy(frame->product, product, sizeof(frame->product)); | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL(hdmi_spd_infoframe_init); | ||
|
||
/** | ||
* hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer | ||
* @frame: HDMI SPD infoframe | ||
* @buffer: destination buffer | ||
* @size: size of buffer | ||
* | ||
* Packs the information contained in the @frame structure into a binary | ||
* representation that can be written into the corresponding controller | ||
* registers. 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) | ||
{ | ||
u8 *ptr = buffer; | ||
size_t length; | ||
|
||
length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; | ||
|
||
if (size < length) | ||
return -ENOSPC; | ||
|
||
memset(buffer, 0, length); | ||
|
||
ptr[0] = frame->type; | ||
ptr[1] = frame->version; | ||
ptr[2] = frame->length; | ||
ptr[3] = 0; /* checksum */ | ||
|
||
/* start infoframe payload */ | ||
ptr += HDMI_INFOFRAME_HEADER_SIZE; | ||
|
||
memcpy(ptr, frame->vendor, sizeof(frame->vendor)); | ||
memcpy(ptr + 8, frame->product, sizeof(frame->product)); | ||
|
||
ptr[24] = frame->sdi; | ||
|
||
hdmi_infoframe_checksum(buffer, length); | ||
|
||
return length; | ||
} | ||
EXPORT_SYMBOL(hdmi_spd_infoframe_pack); | ||
|
||
/** | ||
* hdmi_audio_infoframe_init() - initialize an HDMI audio infoframe | ||
* @frame: HDMI audio infoframe | ||
* | ||
* Returns 0 on success or a negative error code on failure. | ||
*/ | ||
int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame) | ||
{ | ||
memset(frame, 0, sizeof(*frame)); | ||
|
||
frame->type = HDMI_INFOFRAME_TYPE_AUDIO; | ||
frame->version = 1; | ||
frame->length = 10; | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL(hdmi_audio_infoframe_init); | ||
|
||
/** | ||
* hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer | ||
* @frame: HDMI audio infoframe | ||
* @buffer: destination buffer | ||
* @size: size of buffer | ||
* | ||
* Packs the information contained in the @frame structure into a binary | ||
* representation that can be written into the corresponding controller | ||
* registers. 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) | ||
{ | ||
unsigned char channels; | ||
u8 *ptr = buffer; | ||
size_t length; | ||
|
||
length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; | ||
|
||
if (size < length) | ||
return -ENOSPC; | ||
|
||
memset(buffer, 0, length); | ||
|
||
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_infoframe_checksum(buffer, length); | ||
|
||
return length; | ||
} | ||
EXPORT_SYMBOL(hdmi_audio_infoframe_pack); | ||
|
||
/** | ||
* hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary | ||
* buffer | ||
* @frame: HDMI vendor infoframe | ||
* @buffer: destination buffer | ||
* @size: size of buffer | ||
* | ||
* Packs the information contained in the @frame structure into a binary | ||
* representation that can be written into the corresponding controller | ||
* registers. 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) | ||
{ | ||
u8 *ptr = buffer; | ||
size_t length; | ||
|
||
length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; | ||
|
||
if (size < length) | ||
return -ENOSPC; | ||
|
||
memset(buffer, 0, length); | ||
|
||
ptr[0] = frame->type; | ||
ptr[1] = frame->version; | ||
ptr[2] = frame->length; | ||
ptr[3] = 0; /* checksum */ | ||
|
||
memcpy(&ptr[HDMI_INFOFRAME_HEADER_SIZE], frame->data, frame->length); | ||
|
||
hdmi_infoframe_checksum(buffer, length); | ||
|
||
return length; | ||
} | ||
EXPORT_SYMBOL(hdmi_vendor_infoframe_pack); |
Oops, something went wrong.