548 lines
15 KiB
C
548 lines
15 KiB
C
/* $NetBSD: hdmi.h,v 1.5 2014/11/24 01:27:07 riastradh Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2014 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Taylor R. Campbell.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef _LINUX_HDMI_H_
|
|
#define _LINUX_HDMI_H_
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/errno.h>
|
|
#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,
|
|
};
|
|
|
|
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,
|
|
};
|
|
|
|
enum hdmi_audio_coding_type {
|
|
HDMI_AUDIO_CODING_TYPE_STREAM = 0,
|
|
HDMI_AUDIO_CODING_TYPE_PCM = 1,
|
|
HDMI_AUDIO_CODING_TYPE_AC3 = 2,
|
|
HDMI_AUDIO_CODING_TYPE_MPEG1 = 3,
|
|
HDMI_AUDIO_CODING_TYPE_MP3 = 4,
|
|
HDMI_AUDIO_CODING_TYPE_MPEG2 = 5,
|
|
HDMI_AUDIO_CODING_TYPE_AAC_LC = 6,
|
|
HDMI_AUDIO_CODING_TYPE_DTS = 7,
|
|
HDMI_AUDIO_CODING_TYPE_ATRAC = 8,
|
|
HDMI_AUDIO_CODING_TYPE_DSD = 9,
|
|
HDMI_AUDIO_CODING_TYPE_EAC3 = 10,
|
|
HDMI_AUDIO_CODING_TYPE_DTS_HD = 11,
|
|
HDMI_AUDIO_CODING_TYPE_MLP = 12,
|
|
HDMI_AUDIO_CODING_TYPE_DST = 13,
|
|
HDMI_AUDIO_CODING_TYPE_WMA_PRO = 14,
|
|
};
|
|
|
|
enum hdmi_audio_coding_type_ext {
|
|
HDMI_AUDIO_CODING_TYPE_EXT_STREAM = 0,
|
|
HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC = 1,
|
|
HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2 = 2,
|
|
HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND = 3,
|
|
};
|
|
|
|
enum hdmi_audio_sample_frequency {
|
|
HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM = 0,
|
|
HDMI_AUDIO_SAMPLE_FREQUENCY_32000 = 1,
|
|
HDMI_AUDIO_SAMPLE_FREQUENCY_44100 = 2,
|
|
HDMI_AUDIO_SAMPLE_FREQUENCY_48000 = 3,
|
|
HDMI_AUDIO_SAMPLE_FREQUENCY_88200 = 4,
|
|
HDMI_AUDIO_SAMPLE_FREQUENCY_96000 = 5,
|
|
HDMI_AUDIO_SAMPLE_FREQUENCY_176400 = 6,
|
|
HDMI_AUDIO_SAMPLE_FREQUENCY_192000 = 7,
|
|
};
|
|
|
|
enum hdmi_audio_sample_size {
|
|
HDMI_AUDIO_SAMPLE_SIZE_STREAM = 0,
|
|
HDMI_AUDIO_SAMPLE_SIZE_16 = 1,
|
|
HDMI_AUDIO_SAMPLE_SIZE_20 = 2,
|
|
HDMI_AUDIO_SAMPLE_SIZE_24 = 3,
|
|
};
|
|
|
|
enum hdmi_colorimetry {
|
|
HDMI_COLORIMETRY_NONE = 0,
|
|
HDMI_COLORIMETRY_ITU_601 = 1,
|
|
HDMI_COLORIMETRY_ITU_709 = 2,
|
|
HDMI_COLORIMETRY_EXTENDED = 3,
|
|
};
|
|
|
|
enum hdmi_colorspace {
|
|
HDMI_COLORSPACE_RGB = 0,
|
|
HDMI_COLORSPACE_YUV422 = 1,
|
|
HDMI_COLORSPACE_YUV444 = 2,
|
|
};
|
|
|
|
enum hdmi_content_type {
|
|
HDMI_CONTENT_TYPE_NONE = 0,
|
|
HDMI_CONTENT_TYPE_PHOTO = 1,
|
|
HDMI_CONTENT_TYPE_CINEMA = 2,
|
|
HDMI_CONTENT_TYPE_GAME = 3,
|
|
};
|
|
|
|
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,
|
|
};
|
|
|
|
enum hdmi_nups {
|
|
HDMI_NUPS_UNKNOWN = 0,
|
|
HDMI_NUPS_HORIZONTAL = 1,
|
|
HDMI_NUPS_VERTICAL = 2,
|
|
HDMI_NUPS_BOTH = 3,
|
|
};
|
|
|
|
enum hdmi_picture_aspect {
|
|
HDMI_PICTURE_ASPECT_NONE = 0,
|
|
HDMI_PICTURE_ASPECT_4_3 = 1,
|
|
HDMI_PICTURE_ASPECT_16_9 = 2,
|
|
};
|
|
|
|
enum hdmi_quantization_range {
|
|
HDMI_QUANTIZATION_RANGE_DEFAULT = 0,
|
|
HDMI_QUANTIZATION_RANGE_LIMITED = 1,
|
|
HDMI_QUANTIZATION_RANGE_FULL = 2,
|
|
};
|
|
|
|
enum hdmi_scan_mode {
|
|
HDMI_SCAN_MODE_NONE = 0,
|
|
HDMI_SCAN_MODE_OVERSCAN = 1,
|
|
HDMI_SCAN_MODE_UNDERSCAN = 2,
|
|
};
|
|
|
|
enum hdmi_ycc_quantization_range {
|
|
HDMI_YCC_QUANTIZATION_RANGE_LIMITED = 0,
|
|
HDMI_YCC_QUANTIZATION_RANGE_FULL = 1,
|
|
};
|
|
|
|
enum hdmi_infoframe_type {
|
|
HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
|
|
HDMI_INFOFRAME_TYPE_AVI = 0x82,
|
|
HDMI_INFOFRAME_TYPE_SPD = 0x83,
|
|
HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
|
|
};
|
|
|
|
#define HDMI_INFOFRAME_SIZE(TYPE) \
|
|
(HDMI_INFOFRAME_HEADER_SIZE + HDMI_##TYPE##_INFOFRAME_SIZE)
|
|
|
|
#define HDMI_INFOFRAME_HEADER_SIZE 4
|
|
struct hdmi_infoframe_header {
|
|
enum hdmi_infoframe_type type;
|
|
uint8_t version;
|
|
uint8_t length;
|
|
/* checksum */
|
|
};
|
|
|
|
static inline void
|
|
hdmi_infoframe_header_init(struct hdmi_infoframe_header *header,
|
|
enum hdmi_infoframe_type type, uint8_t vers, uint8_t length)
|
|
{
|
|
|
|
header->type = type;
|
|
header->version = vers;
|
|
header->length = length;
|
|
}
|
|
|
|
static inline int
|
|
hdmi_infoframe_header_pack(const struct hdmi_infoframe_header *header,
|
|
uint8_t length, void *buf, size_t size)
|
|
{
|
|
uint8_t *const p = buf;
|
|
|
|
if (length < HDMI_INFOFRAME_HEADER_SIZE)
|
|
return -ENOSPC;
|
|
if (size < length)
|
|
return -ENOSPC;
|
|
|
|
p[0] = header->type;
|
|
p[1] = header->version;
|
|
p[2] = (length - HDMI_INFOFRAME_HEADER_SIZE);
|
|
p[3] = 0; /* checksum */
|
|
|
|
return HDMI_INFOFRAME_HEADER_SIZE;
|
|
}
|
|
|
|
static inline void
|
|
hdmi_infoframe_checksum(void *buf, size_t length)
|
|
{
|
|
uint8_t *p = buf;
|
|
uint8_t checksum = 0;
|
|
|
|
while (length--)
|
|
checksum = *p++;
|
|
|
|
p = buf;
|
|
p[3] = (256 - checksum);
|
|
}
|
|
|
|
#define HDMI_AUDIO_INFOFRAME_SIZE 10
|
|
struct hdmi_audio_infoframe {
|
|
struct hdmi_infoframe_header header;
|
|
uint8_t channels;
|
|
enum hdmi_audio_coding_type coding_type;
|
|
enum hdmi_audio_sample_size sample_size;
|
|
enum hdmi_audio_sample_frequency sample_frequency;
|
|
enum hdmi_audio_coding_type_ext coding_type_ext;
|
|
uint8_t channel_allocation;
|
|
uint8_t level_shift_value;
|
|
bool downmix_inhibit;
|
|
};
|
|
|
|
static inline int
|
|
hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
|
|
{
|
|
static const struct hdmi_audio_infoframe zero_frame;
|
|
|
|
*frame = zero_frame;
|
|
|
|
hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AUDIO,
|
|
1, HDMI_AUDIO_INFOFRAME_SIZE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline ssize_t
|
|
hdmi_audio_infoframe_pack(const struct hdmi_audio_infoframe *frame, void *buf,
|
|
size_t size)
|
|
{
|
|
const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
|
|
HDMI_AUDIO_INFOFRAME_SIZE;
|
|
uint8_t channels = 0;
|
|
uint8_t *p = buf;
|
|
int ret;
|
|
|
|
KASSERT(frame->header.length == HDMI_AUDIO_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;
|
|
|
|
if (frame->channels >= 2)
|
|
channels = frame->channels - 1;
|
|
|
|
p[0] = __SHIFTIN(frame->coding_type, __BITS(7,4));
|
|
p[0] |= __SHIFTIN(channels, __BITS(2,0));
|
|
|
|
p[1] = __SHIFTIN(frame->sample_frequency, __BITS(4,2));
|
|
p[1] |= __SHIFTIN(frame->sample_size, __BITS(1,0));
|
|
|
|
p[2] = __SHIFTIN(frame->coding_type_ext, __BITS(5,0));
|
|
|
|
p[3] = __SHIFTIN(frame->level_shift_value, __BITS(6, 3));
|
|
|
|
p[4] = __SHIFTIN(frame->downmix_inhibit? 1 : 0, __BIT(7));
|
|
|
|
/* XXX p[5], p[6], p[7], p[8], p[9]? */
|
|
CTASSERT(HDMI_AUDIO_INFOFRAME_SIZE == 10);
|
|
|
|
hdmi_infoframe_checksum(buf, length);
|
|
|
|
return length;
|
|
}
|
|
|
|
#define HDMI_AVI_INFOFRAME_SIZE 13
|
|
struct hdmi_avi_infoframe {
|
|
struct hdmi_infoframe_header header;
|
|
enum hdmi_colorspace colorspace;
|
|
enum hdmi_scan_mode scan_mode;
|
|
enum hdmi_colorimetry colorimetry;
|
|
enum hdmi_picture_aspect picture_aspect;
|
|
enum hdmi_active_aspect active_aspect;
|
|
bool itc;
|
|
enum hdmi_extended_colorimetry extended_colorimetry;
|
|
enum hdmi_quantization_range quantization_range;
|
|
enum hdmi_nups nups;
|
|
uint8_t video_code;
|
|
enum hdmi_ycc_quantization_range ycc_quantization_range;
|
|
enum hdmi_content_type content_type;
|
|
uint8_t pixel_repeat;
|
|
uint16_t top_bar;
|
|
uint16_t bottom_bar;
|
|
uint16_t left_bar;
|
|
uint16_t right_bar;
|
|
};
|
|
|
|
static inline int
|
|
hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
|
|
{
|
|
static const struct hdmi_avi_infoframe zero_frame;
|
|
|
|
*frame = zero_frame;
|
|
|
|
hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AVI, 2,
|
|
HDMI_AVI_INFOFRAME_SIZE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline ssize_t
|
|
hdmi_avi_infoframe_pack(const struct hdmi_avi_infoframe *frame, void *buf,
|
|
size_t size)
|
|
{
|
|
const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
|
|
HDMI_AVI_INFOFRAME_SIZE;
|
|
uint8_t *p = buf;
|
|
int ret;
|
|
|
|
KASSERT(frame->header.length == HDMI_AVI_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] = __SHIFTIN(frame->colorspace, __BITS(6,5));
|
|
p[0] |= __SHIFTIN(frame->active_aspect & 0xf? 1 : 0, __BIT(4));
|
|
p[0] |= __SHIFTIN(frame->top_bar || frame->bottom_bar, __BIT(3));
|
|
p[0] |= __SHIFTIN(frame->left_bar || frame->right_bar, __BIT(2));
|
|
p[0] |= __SHIFTIN(frame->scan_mode, __BITS(1,0));
|
|
|
|
p[1] = __SHIFTIN(frame->colorimetry, __BITS(7,6));
|
|
p[1] |= __SHIFTIN(frame->picture_aspect, __BITS(5,4));
|
|
p[1] |= __SHIFTIN(frame->active_aspect, __BITS(3,0));
|
|
|
|
p[2] = __SHIFTIN(frame->itc? 1 : 0, __BIT(7));
|
|
p[2] |= __SHIFTIN(frame->extended_colorimetry, __BITS(6,4));
|
|
p[2] |= __SHIFTIN(frame->quantization_range, __BITS(3,2));
|
|
p[2] |= __SHIFTIN(frame->nups, __BITS(1,0));
|
|
|
|
p[3] = frame->video_code;
|
|
|
|
p[4] = __SHIFTIN(frame->ycc_quantization_range, __BITS(7,6));
|
|
p[4] |= __SHIFTIN(frame->content_type, __BITS(5,4));
|
|
p[4] |= __SHIFTIN(frame->pixel_repeat, __BITS(3,0));
|
|
|
|
le16enc(&p[5], frame->top_bar);
|
|
le16enc(&p[7], frame->bottom_bar);
|
|
le16enc(&p[9], frame->left_bar);
|
|
le16enc(&p[11], frame->right_bar);
|
|
CTASSERT(HDMI_AVI_INFOFRAME_SIZE == 13);
|
|
|
|
hdmi_infoframe_checksum(buf, length);
|
|
|
|
return length;
|
|
}
|
|
|
|
#define HDMI_SPD_INFOFRAME_SIZE 25
|
|
struct hdmi_spd_infoframe {
|
|
struct hdmi_infoframe_header header;
|
|
char vendor[8];
|
|
char product[16];
|
|
enum hdmi_spd_sdi {
|
|
HDMI_SPD_SDI_UNKNOWN = 0,
|
|
HDMI_SPD_SDI_DSTB = 1,
|
|
HDMI_SPD_SDI_DVDP = 2,
|
|
HDMI_SPD_SDI_DVHS = 3,
|
|
HDMI_SPD_SDI_HDDVR = 4,
|
|
HDMI_SPD_SDI_DVC = 5,
|
|
HDMI_SPD_SDI_DSC = 6,
|
|
HDMI_SPD_SDI_VCD = 7,
|
|
HDMI_SPD_SDI_GAME = 8,
|
|
HDMI_SPD_SDI_PC = 9,
|
|
HDMI_SPD_SDI_BD = 10,
|
|
HDMI_SPD_SDI_SACD = 11,
|
|
HDMI_SPD_SDI_HDDVD = 12,
|
|
HDMI_SPD_SDI_PMP = 13,
|
|
} sdi;
|
|
};
|
|
|
|
static inline int
|
|
hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, const char *vendor,
|
|
const char *product)
|
|
{
|
|
static const struct hdmi_spd_infoframe zero_frame;
|
|
|
|
*frame = zero_frame;
|
|
|
|
hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_SPD,
|
|
1, HDMI_SPD_INFOFRAME_SIZE);
|
|
|
|
(void)strlcpy(frame->vendor, vendor, sizeof(frame->vendor));
|
|
(void)strlcpy(frame->product, product, sizeof(frame->product));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline ssize_t
|
|
hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buf,
|
|
size_t size)
|
|
{
|
|
const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
|
|
HDMI_SPD_INFOFRAME_SIZE;
|
|
uint8_t *p = buf;
|
|
int ret;
|
|
|
|
KASSERT(frame->header.length == HDMI_SPD_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;
|
|
|
|
(void)memcpy(&p[0], frame->vendor, 8);
|
|
(void)memcpy(&p[8], frame->product, 16);
|
|
p[24] = frame->sdi;
|
|
|
|
hdmi_infoframe_checksum(buf, length);
|
|
|
|
return length;
|
|
}
|
|
|
|
#define HDMI_IEEE_OUI 0x000c03
|
|
|
|
struct hdmi_vendor_infoframe {
|
|
struct hdmi_infoframe_header header;
|
|
uint32_t oui;
|
|
uint8_t vic;
|
|
enum hdmi_3d_structure s3d_struct;
|
|
unsigned s3d_ext_data;
|
|
};
|
|
|
|
union hdmi_vendor_any_infoframe {
|
|
struct {
|
|
struct hdmi_infoframe_header header;
|
|
uint32_t oui;
|
|
} any;
|
|
struct hdmi_vendor_infoframe hdmi;
|
|
};
|
|
|
|
static inline int
|
|
hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
|
|
{
|
|
static const struct hdmi_vendor_infoframe zero_frame;
|
|
|
|
*frame = zero_frame;
|
|
|
|
hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_VENDOR,
|
|
1, 0 /* depends on s3d_struct */);
|
|
|
|
frame->oui = HDMI_IEEE_OUI;
|
|
frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int
|
|
hdmi_vendor_infoframe_pack(const struct hdmi_vendor_infoframe *frame,
|
|
void *buf, size_t size)
|
|
{
|
|
uint8_t *p = buf;
|
|
size_t length;
|
|
int ret;
|
|
|
|
/* Exactly one must 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;
|
|
|
|
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] = 0x03;
|
|
p[1] = 0x0c;
|
|
p[2] = 0x00;
|
|
|
|
if (frame->vic == 0) {
|
|
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[9] = __SHIFTIN(frame->s3d_ext_data, __BITS(7,4));
|
|
} else {
|
|
p[3] = __SHIFTIN(0x1, __BITS(6,5));
|
|
p[4] = frame->vic;
|
|
}
|
|
|
|
hdmi_infoframe_checksum(buf, length);
|
|
|
|
return length;
|
|
}
|
|
|
|
union hdmi_infoframe {
|
|
struct hdmi_infoframe_header any;
|
|
struct hdmi_avi_infoframe avi;
|
|
struct hdmi_spd_infoframe spd;
|
|
union hdmi_vendor_any_infoframe vendor;
|
|
};
|
|
|
|
static inline ssize_t
|
|
hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buf, size_t size)
|
|
{
|
|
|
|
switch (frame->any.type) {
|
|
case HDMI_INFOFRAME_TYPE_AVI:
|
|
return hdmi_avi_infoframe_pack(&frame->avi, buf, size);
|
|
case HDMI_INFOFRAME_TYPE_SPD:
|
|
return hdmi_spd_infoframe_pack(&frame->spd, buf, size);
|
|
case HDMI_INFOFRAME_TYPE_VENDOR:
|
|
return hdmi_vendor_infoframe_pack(&frame->vendor.hdmi, buf,
|
|
size);
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
#endif /* _LINUX_HDMI_H_ */
|