Home | History | Annotate | Line # | Download | only in linux
hdmi.h revision 1.14
      1  1.14  riastrad /*	$NetBSD: hdmi.h,v 1.14 2021/12/19 11:45:35 riastradh Exp $	*/
      2   1.1  riastrad 
      3   1.1  riastrad /*-
      4   1.1  riastrad  * Copyright (c) 2014 The NetBSD Foundation, Inc.
      5   1.1  riastrad  * All rights reserved.
      6   1.1  riastrad  *
      7   1.1  riastrad  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1  riastrad  * by Taylor R. Campbell.
      9   1.1  riastrad  *
     10   1.1  riastrad  * Redistribution and use in source and binary forms, with or without
     11   1.1  riastrad  * modification, are permitted provided that the following conditions
     12   1.1  riastrad  * are met:
     13   1.1  riastrad  * 1. Redistributions of source code must retain the above copyright
     14   1.1  riastrad  *    notice, this list of conditions and the following disclaimer.
     15   1.1  riastrad  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1  riastrad  *    notice, this list of conditions and the following disclaimer in the
     17   1.1  riastrad  *    documentation and/or other materials provided with the distribution.
     18   1.1  riastrad  *
     19   1.1  riastrad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1  riastrad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1  riastrad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1  riastrad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1  riastrad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1  riastrad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1  riastrad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1  riastrad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1  riastrad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1  riastrad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1  riastrad  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1  riastrad  */
     31   1.1  riastrad 
     32   1.1  riastrad #ifndef	_LINUX_HDMI_H_
     33   1.1  riastrad #define	_LINUX_HDMI_H_
     34   1.1  riastrad 
     35   1.1  riastrad #include <sys/types.h>
     36   1.1  riastrad #include <sys/param.h>
     37   1.1  riastrad #include <sys/errno.h>
     38   1.1  riastrad #include <sys/systm.h>
     39   1.1  riastrad 
     40   1.1  riastrad enum hdmi_3d_structure {
     41  1.14  riastrad 	HDMI_3D_STRUCTURE_INVALID		= -1,
     42  1.14  riastrad 	HDMI_3D_STRUCTURE_FRAME_PACKING		= 0,
     43  1.14  riastrad 	HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE	= 1,
     44  1.14  riastrad 	HDMI_3D_STRUCTURE_LINE_ALTERNATIVE	= 2,
     45  1.14  riastrad 	HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL	= 3,
     46  1.14  riastrad 	HDMI_3D_STRUCTURE_L_DEPTH		= 4,
     47  1.14  riastrad 	HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH	= 5,
     48  1.14  riastrad 	HDMI_3D_STRUCTURE_TOP_AND_BOTTOM	= 6,
     49  1.14  riastrad 	HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF	= 8,
     50   1.1  riastrad };
     51   1.1  riastrad 
     52   1.1  riastrad enum hdmi_active_aspect {
     53  1.14  riastrad 	HDMI_ACTIVE_ASPECT_NONE			= 0,
     54  1.14  riastrad 	HDMI_ACTIVE_ASPECT_16_9_TOP		= 2,
     55  1.14  riastrad 	HDMI_ACTIVE_ASPECT_14_9_TOP		= 3,
     56  1.14  riastrad 	HDMI_ACTIVE_ASPECT_16_9_CENTER		= 4,
     57  1.14  riastrad 	HDMI_ACTIVE_ASPECT_PICTURE		= 8,
     58  1.14  riastrad 	HDMI_ACTIVE_ASPECT_4_3			= 9,
     59  1.14  riastrad 	HDMI_ACTIVE_ASPECT_16_9			= 10,
     60  1.14  riastrad 	HDMI_ACTIVE_ASPECT_14_9			= 11,
     61  1.14  riastrad 	HDMI_ACTIVE_ASPECT_4_3_SP_14_9		= 13,
     62  1.14  riastrad 	HDMI_ACTIVE_ASPECT_16_9_SP_14_9		= 14,
     63  1.14  riastrad 	HDMI_ACTIVE_ASPECT_16_9_SP_4_3		= 15,
     64   1.1  riastrad };
     65   1.1  riastrad 
     66   1.2  riastrad enum hdmi_audio_coding_type {
     67   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_STREAM		= 0,
     68   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_PCM		= 1,
     69   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_AC3		= 2,
     70   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_MPEG1		= 3,
     71   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_MP3		= 4,
     72   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_MPEG2		= 5,
     73   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_AAC_LC		= 6,
     74   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_DTS		= 7,
     75   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_ATRAC		= 8,
     76   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_DSD		= 9,
     77   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_EAC3		= 10,
     78   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_DTS_HD		= 11,
     79   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_MLP		= 12,
     80   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_DST		= 13,
     81   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_WMA_PRO		= 14,
     82   1.2  riastrad };
     83   1.2  riastrad 
     84   1.2  riastrad enum hdmi_audio_coding_type_ext {
     85   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_EXT_STREAM	= 0,
     86   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC	= 1,
     87   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2	= 2,
     88   1.2  riastrad 	HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND = 3,
     89   1.2  riastrad };
     90   1.2  riastrad 
     91   1.2  riastrad enum hdmi_audio_sample_frequency {
     92   1.2  riastrad 	HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM	= 0,
     93   1.2  riastrad 	HDMI_AUDIO_SAMPLE_FREQUENCY_32000	= 1,
     94   1.2  riastrad 	HDMI_AUDIO_SAMPLE_FREQUENCY_44100	= 2,
     95   1.2  riastrad 	HDMI_AUDIO_SAMPLE_FREQUENCY_48000	= 3,
     96   1.2  riastrad 	HDMI_AUDIO_SAMPLE_FREQUENCY_88200	= 4,
     97   1.2  riastrad 	HDMI_AUDIO_SAMPLE_FREQUENCY_96000	= 5,
     98   1.2  riastrad 	HDMI_AUDIO_SAMPLE_FREQUENCY_176400	= 6,
     99   1.2  riastrad 	HDMI_AUDIO_SAMPLE_FREQUENCY_192000	= 7,
    100   1.2  riastrad };
    101   1.2  riastrad 
    102   1.2  riastrad enum hdmi_audio_sample_size {
    103   1.2  riastrad 	HDMI_AUDIO_SAMPLE_SIZE_STREAM		= 0,
    104   1.2  riastrad 	HDMI_AUDIO_SAMPLE_SIZE_16		= 1,
    105   1.2  riastrad 	HDMI_AUDIO_SAMPLE_SIZE_20		= 2,
    106   1.2  riastrad 	HDMI_AUDIO_SAMPLE_SIZE_24		= 3,
    107   1.2  riastrad };
    108   1.2  riastrad 
    109   1.1  riastrad enum hdmi_colorimetry {
    110   1.1  riastrad 	HDMI_COLORIMETRY_NONE			= 0,
    111   1.1  riastrad 	HDMI_COLORIMETRY_ITU_601		= 1,
    112   1.1  riastrad 	HDMI_COLORIMETRY_ITU_709		= 2,
    113   1.1  riastrad 	HDMI_COLORIMETRY_EXTENDED		= 3,
    114   1.1  riastrad };
    115   1.1  riastrad 
    116   1.1  riastrad enum hdmi_colorspace {
    117   1.1  riastrad 	HDMI_COLORSPACE_RGB			= 0,
    118   1.1  riastrad 	HDMI_COLORSPACE_YUV422			= 1,
    119   1.1  riastrad 	HDMI_COLORSPACE_YUV444			= 2,
    120  1.14  riastrad 	HDMI_COLORSPACE_YUV420			= 3,
    121  1.14  riastrad 	HDMI_COLORSPACE_IDO_DEFINED		= 7,
    122   1.1  riastrad };
    123   1.1  riastrad 
    124   1.1  riastrad enum hdmi_content_type {
    125   1.7  riastrad 	HDMI_CONTENT_TYPE_GRAPHICS		= 0,
    126   1.1  riastrad 	HDMI_CONTENT_TYPE_PHOTO			= 1,
    127   1.1  riastrad 	HDMI_CONTENT_TYPE_CINEMA		= 2,
    128   1.1  riastrad 	HDMI_CONTENT_TYPE_GAME			= 3,
    129   1.1  riastrad };
    130   1.1  riastrad 
    131   1.1  riastrad enum hdmi_extended_colorimetry {
    132   1.1  riastrad 	HDMI_EXTENDED_COLORIMETRY_XV_YCC_601	= 0,
    133   1.1  riastrad 	HDMI_EXTENDED_COLORIMETRY_XV_YCC_709	= 1,
    134   1.1  riastrad 	HDMI_EXTENDED_COLORIMETRY_S_YCC_601	= 2,
    135  1.14  riastrad 	HDMI_EXTENDED_COLORIMETRY_OPYCC_601	= 3,
    136  1.14  riastrad 	HDMI_EXTENDED_COLORIMETRY_OPRGB		= 4,
    137   1.1  riastrad };
    138   1.1  riastrad 
    139   1.1  riastrad enum hdmi_nups {
    140   1.1  riastrad 	HDMI_NUPS_UNKNOWN			= 0,
    141   1.1  riastrad 	HDMI_NUPS_HORIZONTAL			= 1,
    142   1.1  riastrad 	HDMI_NUPS_VERTICAL			= 2,
    143   1.1  riastrad 	HDMI_NUPS_BOTH				= 3,
    144   1.1  riastrad };
    145   1.1  riastrad 
    146   1.1  riastrad enum hdmi_picture_aspect {
    147   1.1  riastrad 	HDMI_PICTURE_ASPECT_NONE		= 0,
    148   1.1  riastrad 	HDMI_PICTURE_ASPECT_4_3			= 1,
    149   1.1  riastrad 	HDMI_PICTURE_ASPECT_16_9		= 2,
    150   1.7  riastrad 	HDMI_PICTURE_ASPECT_64_27		= 3,
    151   1.7  riastrad 	HDMI_PICTURE_ASPECT_256_135		= 4,
    152   1.7  riastrad 	HDMI_PICTURE_ASPECT_RESERVED		= 5,
    153   1.1  riastrad };
    154   1.1  riastrad 
    155   1.1  riastrad enum hdmi_quantization_range {
    156   1.1  riastrad 	HDMI_QUANTIZATION_RANGE_DEFAULT		= 0,
    157   1.1  riastrad 	HDMI_QUANTIZATION_RANGE_LIMITED		= 1,
    158   1.1  riastrad 	HDMI_QUANTIZATION_RANGE_FULL		= 2,
    159   1.1  riastrad };
    160   1.1  riastrad 
    161   1.1  riastrad enum hdmi_scan_mode {
    162   1.1  riastrad 	HDMI_SCAN_MODE_NONE			= 0,
    163   1.1  riastrad 	HDMI_SCAN_MODE_OVERSCAN			= 1,
    164   1.1  riastrad 	HDMI_SCAN_MODE_UNDERSCAN		= 2,
    165   1.1  riastrad };
    166   1.1  riastrad 
    167   1.1  riastrad enum hdmi_ycc_quantization_range {
    168   1.1  riastrad 	HDMI_YCC_QUANTIZATION_RANGE_LIMITED	= 0,
    169   1.1  riastrad 	HDMI_YCC_QUANTIZATION_RANGE_FULL	= 1,
    170   1.1  riastrad };
    171   1.1  riastrad 
    172  1.10  riastrad enum hdmi_packet_type {
    173  1.10  riastrad         HDMI_PACKET_TYPE_NULL = 0x00,
    174  1.10  riastrad         HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN	= 0x01,
    175  1.10  riastrad         HDMI_PACKET_TYPE_AUDIO_SAMPLE		= 0x02,
    176  1.10  riastrad         HDMI_PACKET_TYPE_GENERAL_CONTROL	= 0x03,
    177  1.10  riastrad         HDMI_PACKET_TYPE_ACP			= 0x04,
    178  1.10  riastrad         HDMI_PACKET_TYPE_ISRC1			= 0x05,
    179  1.10  riastrad         HDMI_PACKET_TYPE_ISRC2			= 0x06,
    180  1.10  riastrad         HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE	= 0x07,
    181  1.10  riastrad         HDMI_PACKET_TYPE_DST_AUDIO		= 0x08,
    182  1.10  riastrad         HDMI_PACKET_TYPE_HBR_AUDIO_STREAM	= 0x09,
    183  1.10  riastrad         HDMI_PACKET_TYPE_GAMUT_METADATA		= 0x0a,
    184  1.10  riastrad };
    185  1.10  riastrad 
    186   1.1  riastrad enum hdmi_infoframe_type {
    187   1.1  riastrad 	HDMI_INFOFRAME_TYPE_VENDOR		= 0x81,
    188   1.1  riastrad 	HDMI_INFOFRAME_TYPE_AVI			= 0x82,
    189   1.1  riastrad 	HDMI_INFOFRAME_TYPE_SPD			= 0x83,
    190   1.1  riastrad 	HDMI_INFOFRAME_TYPE_AUDIO		= 0x84,
    191  1.10  riastrad 	HDMI_INFOFRAME_TYPE_DRM			= 0x87,
    192   1.1  riastrad };
    193   1.1  riastrad 
    194   1.9  riastrad enum hdmi_eotf {
    195  1.14  riastrad 	HDMI_EOTF_TRADITIONAL_GAMMA_SDR		= 0,
    196  1.14  riastrad 	HDMI_EOTF_TRADITIONAL_GAMMA_HDR		= 1,
    197  1.14  riastrad 	HDMI_EOTF_SMPTE_ST2084			= 2,
    198  1.14  riastrad 	HDMI_EOTF_BT_2100_HLG			= 3,
    199   1.9  riastrad };
    200   1.9  riastrad 
    201   1.9  riastrad enum hdmi_metadata_type {
    202  1.14  riastrad 	HDMI_STATIC_METADATA_TYPE1		= 1,
    203   1.9  riastrad };
    204   1.9  riastrad 
    205  1.11  riastrad struct hdmi_type1 {
    206  1.11  riastrad 	enum hdmi_eotf			eotf;
    207  1.11  riastrad 	enum hdmi_metadata_type		metadata_type;
    208  1.11  riastrad 	uint16_t			min_cll;
    209  1.11  riastrad 	uint16_t			max_cll;
    210  1.11  riastrad 	uint16_t			max_fall;
    211  1.11  riastrad };
    212  1.11  riastrad 
    213  1.11  riastrad struct hdr_sink_metadata {
    214  1.11  riastrad 	struct hdmi_type1		hdmi_type1;
    215  1.11  riastrad };
    216  1.11  riastrad 
    217   1.1  riastrad #define	HDMI_INFOFRAME_SIZE(TYPE)					      \
    218   1.1  riastrad 	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_##TYPE##_INFOFRAME_SIZE)
    219   1.1  riastrad 
    220   1.1  riastrad #define	HDMI_INFOFRAME_HEADER_SIZE	4
    221   1.1  riastrad struct hdmi_infoframe_header {
    222   1.1  riastrad 	enum hdmi_infoframe_type	type;
    223   1.1  riastrad 	uint8_t				version;
    224   1.1  riastrad 	uint8_t				length;
    225   1.1  riastrad 	/* checksum */
    226   1.1  riastrad };
    227   1.1  riastrad 
    228   1.1  riastrad static inline void
    229   1.1  riastrad hdmi_infoframe_header_init(struct hdmi_infoframe_header *header,
    230   1.1  riastrad     enum hdmi_infoframe_type type, uint8_t vers, uint8_t length)
    231   1.1  riastrad {
    232   1.1  riastrad 
    233   1.1  riastrad 	header->type = type;
    234   1.1  riastrad 	header->version = vers;
    235   1.1  riastrad 	header->length = length;
    236   1.1  riastrad }
    237   1.1  riastrad 
    238   1.1  riastrad static inline int
    239  1.14  riastrad hdmi_infoframe_header_check(const struct hdmi_infoframe_header *header,
    240  1.14  riastrad     enum hdmi_infoframe_type type, uint8_t vers, uint8_t length)
    241  1.14  riastrad {
    242  1.14  riastrad 
    243  1.14  riastrad 	if (header->type != type ||
    244  1.14  riastrad 	    header->version != vers ||
    245  1.14  riastrad 	    header->length != length)
    246  1.14  riastrad 		return -EINVAL;
    247  1.14  riastrad 	return 0;
    248  1.14  riastrad }
    249  1.14  riastrad 
    250  1.14  riastrad static inline int
    251   1.1  riastrad hdmi_infoframe_header_pack(const struct hdmi_infoframe_header *header,
    252   1.1  riastrad     uint8_t length, void *buf, size_t size)
    253   1.1  riastrad {
    254   1.1  riastrad 	uint8_t *const p = buf;
    255   1.1  riastrad 
    256   1.5  riastrad 	if (length < HDMI_INFOFRAME_HEADER_SIZE)
    257   1.5  riastrad 		return -ENOSPC;
    258   1.5  riastrad 	if (size < length)
    259   1.1  riastrad 		return -ENOSPC;
    260   1.1  riastrad 
    261   1.1  riastrad 	p[0] = header->type;
    262   1.1  riastrad 	p[1] = header->version;
    263   1.4  riastrad 	p[2] = (length - HDMI_INFOFRAME_HEADER_SIZE);
    264   1.1  riastrad 	p[3] = 0;		/* checksum */
    265   1.1  riastrad 
    266   1.1  riastrad 	return HDMI_INFOFRAME_HEADER_SIZE;
    267   1.1  riastrad }
    268   1.1  riastrad 
    269  1.14  riastrad static inline uint8_t
    270  1.14  riastrad hdmi_infoframe_checksum(const void *buf, size_t length)
    271   1.1  riastrad {
    272  1.14  riastrad 	const uint8_t *p = buf;
    273   1.1  riastrad 	uint8_t checksum = 0;
    274   1.1  riastrad 
    275   1.1  riastrad 	while (length--)
    276   1.6  jmcneill 		checksum += *p++;
    277   1.1  riastrad 
    278  1.14  riastrad 	return 256 - checksum;
    279  1.14  riastrad }
    280  1.14  riastrad 
    281  1.14  riastrad static inline int
    282  1.14  riastrad hdmi_infoframe_header_unpack(struct hdmi_infoframe_header *header,
    283  1.14  riastrad     const void *buf, size_t size)
    284  1.14  riastrad {
    285  1.14  riastrad 	const uint8_t *const p = buf;
    286  1.14  riastrad 
    287  1.14  riastrad 	if (size < HDMI_INFOFRAME_HEADER_SIZE)
    288  1.14  riastrad 		return -EINVAL;
    289  1.14  riastrad 	if (p[2] > size - HDMI_INFOFRAME_HEADER_SIZE)
    290  1.14  riastrad 		return -EINVAL;
    291  1.14  riastrad 	if (hdmi_infoframe_checksum(buf, p[2] + HDMI_INFOFRAME_HEADER_SIZE))
    292  1.14  riastrad 		return -EINVAL;
    293  1.14  riastrad 
    294  1.14  riastrad 	hdmi_infoframe_header_init(header, p[0], p[1], p[2]);
    295  1.14  riastrad 	return HDMI_INFOFRAME_HEADER_SIZE;
    296  1.14  riastrad }
    297  1.14  riastrad 
    298  1.14  riastrad static inline void
    299  1.14  riastrad hdmi_infoframe_set_checksum(void *buf, size_t length)
    300  1.14  riastrad {
    301  1.14  riastrad 	uint8_t *p = buf;
    302  1.14  riastrad 
    303  1.14  riastrad 	p[3] = hdmi_infoframe_checksum(buf, length);
    304   1.1  riastrad }
    305   1.1  riastrad 
    306   1.2  riastrad #define	HDMI_AUDIO_INFOFRAME_SIZE	10
    307   1.2  riastrad struct hdmi_audio_infoframe {
    308   1.2  riastrad 	struct hdmi_infoframe_header	header;
    309   1.2  riastrad 	uint8_t				channels;
    310   1.2  riastrad 	enum hdmi_audio_coding_type	coding_type;
    311   1.2  riastrad 	enum hdmi_audio_sample_size	sample_size;
    312   1.2  riastrad 	enum hdmi_audio_sample_frequency sample_frequency;
    313   1.2  riastrad 	enum hdmi_audio_coding_type_ext	coding_type_ext;
    314   1.2  riastrad 	uint8_t				channel_allocation;
    315   1.2  riastrad 	uint8_t				level_shift_value;
    316   1.2  riastrad 	bool				downmix_inhibit;
    317   1.2  riastrad };
    318   1.2  riastrad 
    319   1.2  riastrad static inline int
    320   1.2  riastrad hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
    321   1.2  riastrad {
    322   1.2  riastrad 	static const struct hdmi_audio_infoframe zero_frame;
    323   1.2  riastrad 
    324   1.2  riastrad 	*frame = zero_frame;
    325   1.2  riastrad 
    326   1.2  riastrad 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AUDIO,
    327   1.2  riastrad 	    1, HDMI_AUDIO_INFOFRAME_SIZE);
    328   1.2  riastrad 
    329   1.2  riastrad 	return 0;
    330   1.2  riastrad }
    331   1.2  riastrad 
    332   1.2  riastrad static inline ssize_t
    333   1.2  riastrad hdmi_audio_infoframe_pack(const struct hdmi_audio_infoframe *frame, void *buf,
    334   1.2  riastrad     size_t size)
    335   1.2  riastrad {
    336   1.2  riastrad 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
    337   1.2  riastrad 	    HDMI_AUDIO_INFOFRAME_SIZE;
    338   1.2  riastrad 	uint8_t channels = 0;
    339   1.2  riastrad 	uint8_t *p = buf;
    340   1.2  riastrad 	int ret;
    341   1.2  riastrad 
    342   1.2  riastrad 	KASSERT(frame->header.length == HDMI_AUDIO_INFOFRAME_SIZE);
    343   1.2  riastrad 
    344   1.4  riastrad 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
    345   1.2  riastrad 	if (ret < 0)
    346   1.2  riastrad 		return ret;
    347   1.3  riastrad 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
    348   1.2  riastrad 	p += HDMI_INFOFRAME_HEADER_SIZE;
    349   1.2  riastrad 	size -= HDMI_INFOFRAME_HEADER_SIZE;
    350   1.2  riastrad 
    351   1.2  riastrad 	if (frame->channels >= 2)
    352   1.2  riastrad 		channels = frame->channels - 1;
    353   1.2  riastrad 
    354   1.2  riastrad 	p[0] = __SHIFTIN(frame->coding_type, __BITS(7,4));
    355   1.2  riastrad 	p[0] |= __SHIFTIN(channels, __BITS(2,0));
    356   1.2  riastrad 
    357   1.2  riastrad 	p[1] = __SHIFTIN(frame->sample_frequency, __BITS(4,2));
    358   1.2  riastrad 	p[1] |= __SHIFTIN(frame->sample_size, __BITS(1,0));
    359   1.2  riastrad 
    360   1.2  riastrad 	p[2] = __SHIFTIN(frame->coding_type_ext, __BITS(5,0));
    361   1.2  riastrad 
    362  1.14  riastrad 	p[3] = __SHIFTIN(frame->level_shift_value, __BITS(6,3));
    363   1.2  riastrad 
    364   1.2  riastrad 	p[4] = __SHIFTIN(frame->downmix_inhibit? 1 : 0, __BIT(7));
    365   1.2  riastrad 
    366   1.6  jmcneill 	/* PB6 to PB10 are reserved */
    367   1.6  jmcneill 	p[5] = 0;
    368   1.6  jmcneill 	p[6] = 0;
    369   1.6  jmcneill 	p[7] = 0;
    370   1.6  jmcneill 	p[8] = 0;
    371   1.6  jmcneill 	p[9] = 0;
    372   1.6  jmcneill 
    373   1.2  riastrad 	CTASSERT(HDMI_AUDIO_INFOFRAME_SIZE == 10);
    374   1.2  riastrad 
    375  1.14  riastrad 	hdmi_infoframe_set_checksum(buf, length);
    376   1.2  riastrad 
    377   1.2  riastrad 	return length;
    378   1.2  riastrad }
    379   1.2  riastrad 
    380  1.14  riastrad static inline int
    381  1.14  riastrad hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
    382  1.14  riastrad     const void *buf, size_t size)
    383  1.14  riastrad {
    384  1.14  riastrad 	const uint8_t *p = buf;
    385  1.14  riastrad 	int ret;
    386  1.14  riastrad 
    387  1.14  riastrad 	memset(frame, 0, sizeof(*frame));
    388  1.14  riastrad 
    389  1.14  riastrad 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
    390  1.14  riastrad 	if (ret)
    391  1.14  riastrad 		return ret;
    392  1.14  riastrad 	if (frame->header.length != HDMI_AUDIO_INFOFRAME_SIZE)
    393  1.14  riastrad 		return -EINVAL;
    394  1.14  riastrad 	p += HDMI_INFOFRAME_HEADER_SIZE;
    395  1.14  riastrad 	size -= HDMI_INFOFRAME_HEADER_SIZE;
    396  1.14  riastrad 
    397  1.14  riastrad 	frame->coding_type = __SHIFTOUT(p[0], __BITS(7,4));
    398  1.14  riastrad 	frame->channels = __SHIFTOUT(p[0], __BITS(2,0));
    399  1.14  riastrad 
    400  1.14  riastrad 	frame->sample_frequency = __SHIFTOUT(p[1], __BITS(4,2));
    401  1.14  riastrad 	frame->sample_size = __SHIFTOUT(p[1], __BITS(1,0));
    402  1.14  riastrad 
    403  1.14  riastrad 	frame->coding_type_ext = __SHIFTOUT(p[2], __BITS(5,0));
    404  1.14  riastrad 
    405  1.14  riastrad 	frame->level_shift_value = __SHIFTOUT(p[3], __BITS(6,3));
    406  1.14  riastrad 
    407  1.14  riastrad 	frame->downmix_inhibit = __SHIFTOUT(p[4], __BIT(7));
    408  1.14  riastrad 
    409  1.14  riastrad 	return 0;
    410  1.14  riastrad }
    411  1.14  riastrad 
    412   1.1  riastrad #define	HDMI_AVI_INFOFRAME_SIZE		13
    413   1.1  riastrad struct hdmi_avi_infoframe {
    414   1.1  riastrad 	struct hdmi_infoframe_header	header;
    415   1.1  riastrad 	enum hdmi_colorspace		colorspace;
    416   1.1  riastrad 	enum hdmi_scan_mode		scan_mode;
    417   1.1  riastrad 	enum hdmi_colorimetry		colorimetry;
    418   1.1  riastrad 	enum hdmi_picture_aspect	picture_aspect;
    419   1.1  riastrad 	enum hdmi_active_aspect		active_aspect;
    420   1.1  riastrad 	bool				itc;
    421   1.1  riastrad 	enum hdmi_extended_colorimetry	extended_colorimetry;
    422   1.1  riastrad 	enum hdmi_quantization_range	quantization_range;
    423   1.1  riastrad 	enum hdmi_nups			nups;
    424   1.1  riastrad 	uint8_t				video_code;
    425   1.1  riastrad 	enum hdmi_ycc_quantization_range ycc_quantization_range;
    426   1.1  riastrad 	enum hdmi_content_type		content_type;
    427   1.1  riastrad 	uint8_t				pixel_repeat;
    428   1.1  riastrad 	uint16_t			top_bar;
    429   1.1  riastrad 	uint16_t			bottom_bar;
    430   1.1  riastrad 	uint16_t			left_bar;
    431   1.1  riastrad 	uint16_t			right_bar;
    432   1.1  riastrad };
    433   1.1  riastrad 
    434   1.1  riastrad static inline int
    435   1.1  riastrad hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
    436   1.1  riastrad {
    437   1.1  riastrad 	static const struct hdmi_avi_infoframe zero_frame;
    438   1.1  riastrad 
    439   1.1  riastrad 	*frame = zero_frame;
    440   1.1  riastrad 
    441   1.1  riastrad 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AVI, 2,
    442   1.1  riastrad 	    HDMI_AVI_INFOFRAME_SIZE);
    443   1.1  riastrad 
    444   1.1  riastrad 	return 0;
    445   1.1  riastrad }
    446   1.1  riastrad 
    447  1.14  riastrad static inline int
    448  1.14  riastrad hdmi_avi_infoframe_check(const struct hdmi_avi_infoframe *frame)
    449  1.14  riastrad {
    450  1.14  riastrad 	int ret;
    451  1.14  riastrad 
    452  1.14  riastrad 	ret = hdmi_infoframe_header_check(&frame->header,
    453  1.14  riastrad 	    HDMI_INFOFRAME_TYPE_AVI, 2, HDMI_AVI_INFOFRAME_SIZE);
    454  1.14  riastrad 	if (ret)
    455  1.14  riastrad 		return ret;
    456  1.14  riastrad 
    457  1.14  riastrad 	return 0;
    458  1.14  riastrad }
    459  1.14  riastrad 
    460   1.1  riastrad static inline ssize_t
    461   1.1  riastrad hdmi_avi_infoframe_pack(const struct hdmi_avi_infoframe *frame, void *buf,
    462   1.1  riastrad     size_t size)
    463   1.1  riastrad {
    464   1.1  riastrad 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
    465   1.1  riastrad 	    HDMI_AVI_INFOFRAME_SIZE;
    466   1.1  riastrad 	uint8_t *p = buf;
    467   1.1  riastrad 	int ret;
    468   1.1  riastrad 
    469   1.1  riastrad 	KASSERT(frame->header.length == HDMI_AVI_INFOFRAME_SIZE);
    470   1.1  riastrad 
    471   1.4  riastrad 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
    472   1.1  riastrad 	if (ret < 0)
    473   1.1  riastrad 		return ret;
    474   1.3  riastrad 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
    475   1.1  riastrad 	p += HDMI_INFOFRAME_HEADER_SIZE;
    476   1.1  riastrad 	size -= HDMI_INFOFRAME_HEADER_SIZE;
    477   1.1  riastrad 
    478   1.1  riastrad 	p[0] = __SHIFTIN(frame->colorspace, __BITS(6,5));
    479   1.1  riastrad 	p[0] |= __SHIFTIN(frame->active_aspect & 0xf? 1 : 0, __BIT(4));
    480   1.1  riastrad 	p[0] |= __SHIFTIN(frame->top_bar || frame->bottom_bar, __BIT(3));
    481   1.1  riastrad 	p[0] |= __SHIFTIN(frame->left_bar || frame->right_bar, __BIT(2));
    482   1.1  riastrad 	p[0] |= __SHIFTIN(frame->scan_mode, __BITS(1,0));
    483   1.1  riastrad 
    484   1.1  riastrad 	p[1] = __SHIFTIN(frame->colorimetry, __BITS(7,6));
    485   1.1  riastrad 	p[1] |= __SHIFTIN(frame->picture_aspect, __BITS(5,4));
    486   1.1  riastrad 	p[1] |= __SHIFTIN(frame->active_aspect, __BITS(3,0));
    487   1.1  riastrad 
    488   1.1  riastrad 	p[2] = __SHIFTIN(frame->itc? 1 : 0, __BIT(7));
    489   1.1  riastrad 	p[2] |= __SHIFTIN(frame->extended_colorimetry, __BITS(6,4));
    490   1.1  riastrad 	p[2] |= __SHIFTIN(frame->quantization_range, __BITS(3,2));
    491   1.1  riastrad 	p[2] |= __SHIFTIN(frame->nups, __BITS(1,0));
    492   1.1  riastrad 
    493   1.1  riastrad 	p[3] = frame->video_code;
    494   1.1  riastrad 
    495   1.1  riastrad 	p[4] = __SHIFTIN(frame->ycc_quantization_range, __BITS(7,6));
    496   1.1  riastrad 	p[4] |= __SHIFTIN(frame->content_type, __BITS(5,4));
    497   1.1  riastrad 	p[4] |= __SHIFTIN(frame->pixel_repeat, __BITS(3,0));
    498   1.1  riastrad 
    499   1.1  riastrad 	le16enc(&p[5], frame->top_bar);
    500   1.1  riastrad 	le16enc(&p[7], frame->bottom_bar);
    501   1.1  riastrad 	le16enc(&p[9], frame->left_bar);
    502   1.1  riastrad 	le16enc(&p[11], frame->right_bar);
    503   1.1  riastrad 	CTASSERT(HDMI_AVI_INFOFRAME_SIZE == 13);
    504   1.1  riastrad 
    505  1.14  riastrad 	hdmi_infoframe_set_checksum(buf, length);
    506  1.14  riastrad 
    507  1.14  riastrad 	return length;
    508  1.14  riastrad }
    509  1.14  riastrad 
    510  1.14  riastrad static inline int
    511  1.14  riastrad hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame, const void *buf,
    512  1.14  riastrad     size_t size)
    513  1.14  riastrad {
    514  1.14  riastrad 	const uint8_t *p = buf;
    515  1.14  riastrad 	int ret;
    516  1.14  riastrad 
    517  1.14  riastrad 	memset(frame, 0, sizeof(*frame));
    518  1.14  riastrad 
    519  1.14  riastrad 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
    520  1.14  riastrad 	if (ret)
    521  1.14  riastrad 		return ret;
    522  1.14  riastrad 	if (frame->header.length != HDMI_AVI_INFOFRAME_SIZE)
    523  1.14  riastrad 		return -EINVAL;
    524  1.14  riastrad 	p += HDMI_INFOFRAME_HEADER_SIZE;
    525  1.14  riastrad 	size -= HDMI_INFOFRAME_HEADER_SIZE;
    526  1.14  riastrad 
    527  1.14  riastrad 	frame->colorspace = __SHIFTOUT(p[0], __BITS(6,5));
    528  1.14  riastrad 	frame->scan_mode = __SHIFTOUT(p[0], __BITS(1,0));
    529  1.14  riastrad 
    530  1.14  riastrad 	frame->colorimetry = __SHIFTOUT(p[1], __BITS(7,6));
    531  1.14  riastrad 	frame->picture_aspect = __SHIFTOUT(p[1], __BITS(5,4));
    532  1.14  riastrad 	if (p[0] & __BIT(4))
    533  1.14  riastrad 		frame->active_aspect = __SHIFTOUT(p[1], __BITS(3,0));
    534  1.14  riastrad 
    535  1.14  riastrad 	frame->itc = __SHIFTOUT(p[2], __BIT(7));
    536  1.14  riastrad 	frame->extended_colorimetry = __SHIFTOUT(p[2], __BITS(6,4));
    537  1.14  riastrad 	frame->quantization_range = __SHIFTOUT(p[2], __BITS(3,2));
    538  1.14  riastrad 	frame->nups = __SHIFTOUT(p[2], __BITS(1,0));
    539  1.14  riastrad 
    540  1.14  riastrad 	frame->video_code = p[3];
    541  1.14  riastrad 
    542  1.14  riastrad 	frame->ycc_quantization_range = __SHIFTOUT(p[4], __BITS(7,6));
    543  1.14  riastrad 	frame->content_type = __SHIFTOUT(p[4], __BITS(5,4));
    544  1.14  riastrad 	frame->pixel_repeat = __SHIFTOUT(p[4], __BITS(3,0));
    545  1.14  riastrad 
    546  1.14  riastrad 	if (p[0] & __BIT(3)) {
    547  1.14  riastrad 		frame->top_bar = le16dec(&p[5]);
    548  1.14  riastrad 		frame->bottom_bar = le16dec(&p[7]);
    549  1.14  riastrad 	}
    550  1.14  riastrad 	if (p[0] & __BIT(2)) {
    551  1.14  riastrad 		frame->left_bar = le16dec(&p[9]);
    552  1.14  riastrad 		frame->right_bar = le16dec(&p[11]);
    553  1.14  riastrad 	}
    554  1.14  riastrad 
    555  1.14  riastrad 	return 0;
    556  1.14  riastrad }
    557  1.14  riastrad 
    558  1.14  riastrad #define	HDMI_DRM_INFOFRAME_SIZE		26
    559  1.14  riastrad struct hdmi_drm_infoframe {
    560  1.14  riastrad 	struct hdmi_infoframe_header	header;
    561  1.14  riastrad 	enum hdmi_eotf			eotf;
    562  1.14  riastrad 	enum hdmi_metadata_type		metadata_type;
    563  1.14  riastrad 	struct {
    564  1.14  riastrad 		uint16_t	x, y;
    565  1.14  riastrad 	}				display_primaries[3];
    566  1.14  riastrad 	struct {
    567  1.14  riastrad 		uint16_t	x, y;
    568  1.14  riastrad 	}				white_point;
    569  1.14  riastrad 	uint16_t			max_display_mastering_luminance;
    570  1.14  riastrad 	uint16_t			min_display_mastering_luminance;
    571  1.14  riastrad 	uint16_t			max_cll;
    572  1.14  riastrad 	uint16_t			max_fall;
    573  1.14  riastrad };
    574  1.14  riastrad 
    575  1.14  riastrad static inline int
    576  1.14  riastrad hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame)
    577  1.14  riastrad {
    578  1.14  riastrad 	static const struct hdmi_drm_infoframe zero_frame;
    579  1.14  riastrad 
    580  1.14  riastrad 	*frame = zero_frame;
    581  1.14  riastrad 
    582  1.14  riastrad 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_DRM,
    583  1.14  riastrad 	    1, HDMI_DRM_INFOFRAME_SIZE);
    584  1.14  riastrad 
    585  1.14  riastrad 	return 0;
    586  1.14  riastrad }
    587  1.14  riastrad 
    588  1.14  riastrad static inline int
    589  1.14  riastrad hdmi_drm_infoframe_check(const struct hdmi_drm_infoframe *frame)
    590  1.14  riastrad {
    591  1.14  riastrad 	int ret;
    592  1.14  riastrad 
    593  1.14  riastrad 	ret = hdmi_infoframe_header_check(&frame->header,
    594  1.14  riastrad 	    HDMI_INFOFRAME_TYPE_DRM, 1, HDMI_DRM_INFOFRAME_SIZE);
    595  1.14  riastrad 	if (ret)
    596  1.14  riastrad 		return ret;
    597  1.14  riastrad 
    598  1.14  riastrad 	return 0;
    599  1.14  riastrad }
    600  1.14  riastrad 
    601  1.14  riastrad #define	hdmi_drm_infoframe_pack_only	hdmi_drm_infoframe_pack /* XXX */
    602  1.14  riastrad 
    603  1.14  riastrad static inline int
    604  1.14  riastrad hdmi_drm_infoframe_pack(const struct hdmi_drm_infoframe *frame,
    605  1.14  riastrad     void *buf, size_t size)
    606  1.14  riastrad {
    607  1.14  riastrad 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
    608  1.14  riastrad 	    HDMI_DRM_INFOFRAME_SIZE;
    609  1.14  riastrad 	uint8_t *p = buf;
    610  1.14  riastrad 	unsigned i;
    611  1.14  riastrad 	int ret;
    612  1.14  riastrad 
    613  1.14  riastrad 	KASSERT(frame->header.length == HDMI_DRM_INFOFRAME_SIZE);
    614  1.14  riastrad 
    615  1.14  riastrad 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
    616  1.14  riastrad 	if (ret < 0)
    617  1.14  riastrad 		return ret;
    618  1.14  riastrad 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
    619  1.14  riastrad 	p += HDMI_INFOFRAME_HEADER_SIZE;
    620  1.14  riastrad 	size -= HDMI_INFOFRAME_HEADER_SIZE;
    621  1.14  riastrad 
    622  1.14  riastrad 	p[0] = frame->eotf;
    623  1.14  riastrad 	p[1] = frame->metadata_type;
    624  1.14  riastrad 	for (i = 0; i < __arraycount(frame->display_primaries); i++) {
    625  1.14  riastrad 		le16enc(&p[2 + 4*i], frame->display_primaries[i].x);
    626  1.14  riastrad 		le16enc(&p[2 + 4*i + 2], frame->display_primaries[i].y);
    627  1.14  riastrad 	}
    628  1.14  riastrad 	le16enc(&p[14], frame->white_point.x);
    629  1.14  riastrad 	le16enc(&p[16], frame->white_point.y);
    630  1.14  riastrad 	le16enc(&p[18], frame->min_display_mastering_luminance);
    631  1.14  riastrad 	le16enc(&p[20], frame->max_display_mastering_luminance);
    632  1.14  riastrad 	le16enc(&p[22], frame->max_cll);
    633  1.14  riastrad 	le16enc(&p[24], frame->max_fall);
    634  1.14  riastrad 	CTASSERT(HDMI_DRM_INFOFRAME_SIZE == 26);
    635  1.14  riastrad 
    636  1.14  riastrad 	hdmi_infoframe_set_checksum(buf, length);
    637   1.1  riastrad 
    638   1.1  riastrad 	return length;
    639   1.1  riastrad }
    640   1.1  riastrad 
    641  1.14  riastrad static inline int
    642  1.14  riastrad hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe *frame, const void *buf,
    643  1.14  riastrad     size_t size)
    644  1.14  riastrad {
    645  1.14  riastrad 	const uint8_t *p = buf;
    646  1.14  riastrad 	unsigned i;
    647  1.14  riastrad 	int ret;
    648  1.14  riastrad 
    649  1.14  riastrad 	memset(frame, 0, sizeof(*frame));
    650  1.14  riastrad 
    651  1.14  riastrad 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
    652  1.14  riastrad 	if (ret)
    653  1.14  riastrad 		return ret;
    654  1.14  riastrad 	if (frame->header.length != HDMI_DRM_INFOFRAME_SIZE)
    655  1.14  riastrad 		return -EINVAL;
    656  1.14  riastrad 	p += HDMI_INFOFRAME_HEADER_SIZE;
    657  1.14  riastrad 	size -= HDMI_INFOFRAME_HEADER_SIZE;
    658  1.14  riastrad 
    659  1.14  riastrad 	frame->eotf = p[0];
    660  1.14  riastrad 	frame->metadata_type = p[1];
    661  1.14  riastrad 	for (i = 0; i < __arraycount(frame->display_primaries); i++) {
    662  1.14  riastrad 		frame->display_primaries[i].x = le16dec(&p[2 + 4*i]);
    663  1.14  riastrad 		frame->display_primaries[i].y = le16dec(&p[2 + 4*i + 2]);
    664  1.14  riastrad 	}
    665  1.14  riastrad 	frame->white_point.x = le16dec(&p[14]);
    666  1.14  riastrad 	frame->white_point.y = le16dec(&p[16]);
    667  1.14  riastrad 	frame->min_display_mastering_luminance = le16dec(&p[18]);
    668  1.14  riastrad 	frame->max_display_mastering_luminance = le16dec(&p[20]);
    669  1.14  riastrad 	frame->max_cll = le16dec(&p[22]);
    670  1.14  riastrad 	frame->max_fall = le16dec(&p[24]);
    671  1.14  riastrad 
    672  1.14  riastrad 	return 0;
    673  1.14  riastrad }
    674  1.14  riastrad 
    675   1.1  riastrad #define	HDMI_SPD_INFOFRAME_SIZE		25
    676   1.1  riastrad struct hdmi_spd_infoframe {
    677   1.1  riastrad 	struct hdmi_infoframe_header	header;
    678   1.1  riastrad 	char				vendor[8];
    679   1.1  riastrad 	char				product[16];
    680   1.1  riastrad 	enum hdmi_spd_sdi {
    681   1.1  riastrad 	        HDMI_SPD_SDI_UNKNOWN	= 0,
    682   1.1  riastrad 		HDMI_SPD_SDI_DSTB	= 1,
    683   1.1  riastrad 		HDMI_SPD_SDI_DVDP	= 2,
    684   1.1  riastrad 		HDMI_SPD_SDI_DVHS	= 3,
    685   1.1  riastrad 		HDMI_SPD_SDI_HDDVR	= 4,
    686   1.1  riastrad 		HDMI_SPD_SDI_DVC	= 5,
    687   1.1  riastrad 		HDMI_SPD_SDI_DSC	= 6,
    688   1.1  riastrad 		HDMI_SPD_SDI_VCD	= 7,
    689   1.1  riastrad 		HDMI_SPD_SDI_GAME	= 8,
    690   1.1  riastrad 		HDMI_SPD_SDI_PC		= 9,
    691   1.1  riastrad 		HDMI_SPD_SDI_BD		= 10,
    692   1.1  riastrad 		HDMI_SPD_SDI_SACD	= 11,
    693   1.1  riastrad 		HDMI_SPD_SDI_HDDVD	= 12,
    694   1.1  riastrad 		HDMI_SPD_SDI_PMP	= 13,
    695   1.1  riastrad 	}				sdi;
    696   1.1  riastrad };
    697   1.1  riastrad 
    698   1.1  riastrad static inline int
    699   1.1  riastrad hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, const char *vendor,
    700   1.1  riastrad     const char *product)
    701   1.1  riastrad {
    702   1.1  riastrad 	static const struct hdmi_spd_infoframe zero_frame;
    703   1.1  riastrad 
    704   1.1  riastrad 	*frame = zero_frame;
    705   1.1  riastrad 
    706   1.1  riastrad 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_SPD,
    707   1.1  riastrad 	    1, HDMI_SPD_INFOFRAME_SIZE);
    708   1.1  riastrad 
    709  1.12  riastrad 	strncpy(frame->vendor, vendor, sizeof(frame->vendor));
    710  1.12  riastrad 	strncpy(frame->product, product, sizeof(frame->product));
    711   1.1  riastrad 
    712   1.1  riastrad 	return 0;
    713   1.1  riastrad }
    714   1.1  riastrad 
    715  1.14  riastrad static inline int
    716  1.14  riastrad hdmi_spd_infoframe_check(const struct hdmi_spd_infoframe *frame)
    717  1.14  riastrad {
    718  1.14  riastrad 	int ret;
    719  1.14  riastrad 
    720  1.14  riastrad 	ret = hdmi_infoframe_header_check(&frame->header,
    721  1.14  riastrad 	    HDMI_INFOFRAME_TYPE_SPD, 2, HDMI_SPD_INFOFRAME_SIZE);
    722  1.14  riastrad 	if (ret)
    723  1.14  riastrad 		return ret;
    724  1.14  riastrad 
    725  1.14  riastrad 	return 0;
    726  1.14  riastrad }
    727  1.14  riastrad 
    728   1.1  riastrad static inline ssize_t
    729  1.14  riastrad hdmi_spd_infoframe_pack(const struct hdmi_spd_infoframe *frame, void *buf,
    730   1.1  riastrad     size_t size)
    731   1.1  riastrad {
    732   1.1  riastrad 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
    733   1.1  riastrad 	    HDMI_SPD_INFOFRAME_SIZE;
    734   1.1  riastrad 	uint8_t *p = buf;
    735   1.1  riastrad 	int ret;
    736   1.1  riastrad 
    737   1.1  riastrad 	KASSERT(frame->header.length == HDMI_SPD_INFOFRAME_SIZE);
    738   1.1  riastrad 
    739   1.4  riastrad 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
    740   1.1  riastrad 	if (ret < 0)
    741   1.1  riastrad 		return ret;
    742   1.3  riastrad 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
    743   1.1  riastrad 	p += HDMI_INFOFRAME_HEADER_SIZE;
    744   1.1  riastrad 	size -= HDMI_INFOFRAME_HEADER_SIZE;
    745   1.1  riastrad 
    746  1.14  riastrad 	memcpy(&p[0], frame->vendor, 8);
    747  1.14  riastrad 	memcpy(&p[8], frame->product, 16);
    748   1.1  riastrad 	p[24] = frame->sdi;
    749  1.11  riastrad 	CTASSERT(HDMI_SPD_INFOFRAME_SIZE == 25);
    750   1.1  riastrad 
    751  1.14  riastrad 	hdmi_infoframe_set_checksum(buf, length);
    752   1.1  riastrad 
    753   1.1  riastrad 	return length;
    754   1.1  riastrad }
    755   1.1  riastrad 
    756  1.14  riastrad static inline int
    757  1.14  riastrad hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame, const void *buf,
    758  1.14  riastrad     size_t size)
    759  1.14  riastrad {
    760  1.14  riastrad 	const uint8_t *p = buf;
    761  1.14  riastrad 	int ret;
    762  1.14  riastrad 
    763  1.14  riastrad 	memset(frame, 0, sizeof(*frame));
    764  1.14  riastrad 
    765  1.14  riastrad 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
    766  1.14  riastrad 	if (ret)
    767  1.14  riastrad 		return ret;
    768  1.14  riastrad 	if (frame->header.length != HDMI_SPD_INFOFRAME_SIZE)
    769  1.14  riastrad 		return -EINVAL;
    770  1.14  riastrad 	p += HDMI_INFOFRAME_HEADER_SIZE;
    771  1.14  riastrad 	size -= HDMI_INFOFRAME_HEADER_SIZE;
    772  1.14  riastrad 
    773  1.14  riastrad 	memcpy(frame->vendor, &p[0], 8);
    774  1.14  riastrad 	memcpy(frame->product, &p[8], 8);
    775  1.14  riastrad 	frame->sdi = p[24];
    776  1.14  riastrad 
    777  1.14  riastrad 	return 0;
    778  1.14  riastrad }
    779  1.14  riastrad 
    780   1.7  riastrad #define	HDMI_IEEE_OUI		0x000c03
    781   1.7  riastrad #define	HDMI_FORUM_IEEE_OUI	0xc45dd8
    782   1.1  riastrad 
    783   1.1  riastrad struct hdmi_vendor_infoframe {
    784   1.1  riastrad 	struct hdmi_infoframe_header	header;
    785   1.1  riastrad 	uint32_t			oui;
    786   1.1  riastrad 	uint8_t				vic;
    787   1.1  riastrad 	enum hdmi_3d_structure		s3d_struct;
    788   1.1  riastrad 	unsigned			s3d_ext_data;
    789   1.1  riastrad };
    790   1.1  riastrad 
    791   1.1  riastrad union hdmi_vendor_any_infoframe {
    792   1.1  riastrad 	struct {
    793   1.1  riastrad 		struct hdmi_infoframe_header	header;
    794   1.1  riastrad 		uint32_t			oui;
    795   1.1  riastrad 	}				any;
    796   1.1  riastrad 	struct hdmi_vendor_infoframe	hdmi;
    797   1.1  riastrad };
    798   1.1  riastrad 
    799   1.1  riastrad static inline int
    800   1.1  riastrad hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
    801   1.1  riastrad {
    802   1.1  riastrad 	static const struct hdmi_vendor_infoframe zero_frame;
    803   1.1  riastrad 
    804   1.1  riastrad 	*frame = zero_frame;
    805   1.1  riastrad 
    806   1.1  riastrad 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_VENDOR,
    807   1.1  riastrad 	    1, 0 /* depends on s3d_struct */);
    808   1.1  riastrad 
    809   1.1  riastrad 	frame->oui = HDMI_IEEE_OUI;
    810   1.1  riastrad 	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
    811   1.1  riastrad 
    812   1.1  riastrad 	return 0;
    813   1.1  riastrad }
    814   1.1  riastrad 
    815  1.14  riastrad static inline size_t
    816  1.14  riastrad hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame)
    817  1.14  riastrad {
    818  1.14  riastrad 
    819  1.14  riastrad 	if (frame->vic) {
    820  1.14  riastrad 		return 5;
    821  1.14  riastrad 	} else if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
    822  1.14  riastrad 		if (frame->s3d_struct < HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
    823  1.14  riastrad 			return 5;
    824  1.14  riastrad 		else
    825  1.14  riastrad 			return 6;
    826  1.14  riastrad 	} else {
    827  1.14  riastrad 		return 4;
    828  1.14  riastrad 	}
    829  1.14  riastrad }
    830  1.14  riastrad 
    831  1.14  riastrad static inline int
    832  1.14  riastrad hdmi_vendor_infoframe_check(const struct hdmi_vendor_infoframe *frame)
    833  1.14  riastrad {
    834  1.14  riastrad 
    835  1.14  riastrad 	if (frame->header.type != HDMI_INFOFRAME_TYPE_VENDOR ||
    836  1.14  riastrad 	    frame->header.version != 1)
    837  1.14  riastrad 		return -EINVAL;
    838  1.14  riastrad 	/* frame->header.length not used when packing */
    839  1.14  riastrad 
    840  1.14  riastrad 	/* At most one may be supplied.  */
    841  1.14  riastrad 	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
    842  1.14  riastrad 		return -EINVAL;
    843  1.14  riastrad 
    844  1.14  riastrad 	return 0;
    845  1.14  riastrad }
    846  1.14  riastrad 
    847   1.1  riastrad static inline int
    848   1.1  riastrad hdmi_vendor_infoframe_pack(const struct hdmi_vendor_infoframe *frame,
    849   1.1  riastrad     void *buf, size_t size)
    850   1.1  riastrad {
    851   1.1  riastrad 	uint8_t *p = buf;
    852   1.1  riastrad 	size_t length;
    853   1.1  riastrad 	int ret;
    854   1.1  riastrad 
    855  1.14  riastrad 	/* At most one may be supplied.  */
    856  1.14  riastrad 	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
    857   1.1  riastrad 		return -EINVAL;
    858   1.1  riastrad 
    859  1.14  riastrad 	length = HDMI_INFOFRAME_HEADER_SIZE;
    860  1.14  riastrad 	length += hdmi_vendor_infoframe_length(frame);
    861   1.1  riastrad 
    862   1.4  riastrad 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
    863   1.1  riastrad 	if (ret < 0)
    864   1.1  riastrad 		return ret;
    865   1.3  riastrad 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
    866   1.1  riastrad 	p += HDMI_INFOFRAME_HEADER_SIZE;
    867   1.1  riastrad 	size -= HDMI_INFOFRAME_HEADER_SIZE;
    868   1.1  riastrad 
    869   1.1  riastrad 	p[0] = 0x03;
    870   1.1  riastrad 	p[1] = 0x0c;
    871   1.1  riastrad 	p[2] = 0x00;
    872   1.1  riastrad 
    873  1.14  riastrad 	if (frame->vic) {
    874  1.14  riastrad 		p[3] = __SHIFTIN(0x1, __BITS(6,5));
    875  1.14  riastrad 		p[4] = frame->vic;
    876  1.14  riastrad 	} else if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
    877   1.1  riastrad 		p[3] = __SHIFTIN(0x2, __BITS(6,5));
    878   1.1  riastrad 		p[4] = __SHIFTIN(frame->s3d_struct, __BITS(7,4));
    879   1.1  riastrad 		if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
    880  1.13  riastrad 			p[5] = __SHIFTIN(frame->s3d_ext_data, __BITS(7,4));
    881   1.1  riastrad 	} else {
    882  1.14  riastrad 		p[3] = __SHIFTIN(0x0, __BITS(6,5));
    883   1.1  riastrad 	}
    884   1.1  riastrad 
    885  1.14  riastrad 	hdmi_infoframe_set_checksum(buf, length);
    886   1.1  riastrad 
    887   1.1  riastrad 	return length;
    888   1.1  riastrad }
    889   1.1  riastrad 
    890  1.11  riastrad static inline int
    891  1.14  riastrad hdmi_vendor_infoframe_unpack(struct hdmi_vendor_infoframe *frame,
    892  1.14  riastrad     const void *buf, size_t size)
    893  1.11  riastrad {
    894  1.14  riastrad 	const uint8_t *p = buf;
    895  1.11  riastrad 	int ret;
    896  1.11  riastrad 
    897  1.14  riastrad 	memset(frame, 0, sizeof(*frame));
    898  1.11  riastrad 
    899  1.14  riastrad 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
    900  1.14  riastrad 	if (ret)
    901  1.11  riastrad 		return ret;
    902  1.14  riastrad 	if (frame->header.length < 4)
    903  1.14  riastrad 		return -EINVAL;
    904  1.11  riastrad 	p += HDMI_INFOFRAME_HEADER_SIZE;
    905  1.11  riastrad 	size -= HDMI_INFOFRAME_HEADER_SIZE;
    906  1.11  riastrad 
    907  1.14  riastrad 	if (p[0] != 0x03 || p[1] != 0x0c || p[2] != 0x00)
    908  1.14  riastrad 		return -EINVAL;
    909  1.14  riastrad 
    910  1.14  riastrad 	switch (__SHIFTOUT(p[3], __BITS(6,5))) {
    911  1.14  riastrad 	case 0x0:
    912  1.14  riastrad 		if (frame->header.length != 4)
    913  1.14  riastrad 			return -EINVAL;
    914  1.14  riastrad 		break;
    915  1.14  riastrad 	case 0x1:
    916  1.14  riastrad 		if (frame->header.length != 5)
    917  1.14  riastrad 			return -EINVAL;
    918  1.14  riastrad 		frame->vic = p[4];
    919  1.14  riastrad 		break;
    920  1.14  riastrad 	case 0x2:
    921  1.14  riastrad 		if (frame->header.length < 5)
    922  1.14  riastrad 			return -EINVAL;
    923  1.14  riastrad 		frame->s3d_struct = __SHIFTOUT(p[4], __BITS(7,4));
    924  1.14  riastrad 		if (frame->s3d_struct < HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
    925  1.14  riastrad 			if (frame->header.length != 5)
    926  1.14  riastrad 				return -EINVAL;
    927  1.14  riastrad 		} else {
    928  1.14  riastrad 			if (frame->header.length != 6)
    929  1.14  riastrad 				return -EINVAL;
    930  1.14  riastrad 			frame->s3d_ext_data = __SHIFTOUT(p[5], __BITS(7,4));
    931  1.14  riastrad 		}
    932  1.14  riastrad 		break;
    933  1.14  riastrad 	default:
    934  1.14  riastrad 		return -EINVAL;
    935  1.11  riastrad 	}
    936  1.11  riastrad 
    937  1.14  riastrad 	return 0;
    938  1.11  riastrad }
    939  1.11  riastrad 
    940   1.1  riastrad union hdmi_infoframe {
    941   1.1  riastrad 	struct hdmi_infoframe_header	any;
    942   1.1  riastrad 	struct hdmi_avi_infoframe	avi;
    943  1.11  riastrad 	struct hdmi_drm_infoframe	drm;
    944   1.1  riastrad 	struct hdmi_spd_infoframe	spd;
    945   1.1  riastrad 	union hdmi_vendor_any_infoframe	vendor;
    946   1.1  riastrad };
    947   1.1  riastrad 
    948  1.14  riastrad #define	hdmi_infoframe_pack_only	hdmi_infoframe_pack /* XXX */
    949  1.14  riastrad 
    950   1.1  riastrad static inline ssize_t
    951  1.14  riastrad hdmi_infoframe_pack(const union hdmi_infoframe *frame, void *buf, size_t size)
    952   1.1  riastrad {
    953   1.1  riastrad 
    954   1.1  riastrad 	switch (frame->any.type) {
    955   1.1  riastrad 	case HDMI_INFOFRAME_TYPE_AVI:
    956   1.1  riastrad 		return hdmi_avi_infoframe_pack(&frame->avi, buf, size);
    957  1.11  riastrad 	case HDMI_INFOFRAME_TYPE_DRM:
    958  1.11  riastrad 		return hdmi_drm_infoframe_pack(&frame->drm, buf, size);
    959   1.1  riastrad 	case HDMI_INFOFRAME_TYPE_SPD:
    960   1.1  riastrad 		return hdmi_spd_infoframe_pack(&frame->spd, buf, size);
    961   1.1  riastrad 	case HDMI_INFOFRAME_TYPE_VENDOR:
    962   1.1  riastrad 		return hdmi_vendor_infoframe_pack(&frame->vendor.hdmi, buf,
    963   1.1  riastrad 		    size);
    964   1.1  riastrad 	default:
    965   1.1  riastrad 		return -EINVAL;
    966   1.1  riastrad 	}
    967   1.1  riastrad }
    968   1.1  riastrad 
    969  1.14  riastrad static inline int
    970  1.14  riastrad hdmi_infoframe_unpack(union hdmi_infoframe *frame, const void *buf,
    971  1.14  riastrad     size_t size)
    972  1.14  riastrad {
    973  1.14  riastrad 	struct hdmi_infoframe_header header;
    974  1.14  riastrad 	int ret;
    975  1.14  riastrad 
    976  1.14  riastrad 	ret = hdmi_infoframe_header_unpack(&header, buf, size);
    977  1.14  riastrad 	if (ret)
    978  1.14  riastrad 		return ret;
    979  1.14  riastrad 	switch (header.type) {
    980  1.14  riastrad 	case HDMI_INFOFRAME_TYPE_AVI:
    981  1.14  riastrad 		return hdmi_avi_infoframe_unpack(&frame->avi, buf, size);
    982  1.14  riastrad 	case HDMI_INFOFRAME_TYPE_DRM:
    983  1.14  riastrad 		return hdmi_drm_infoframe_unpack(&frame->drm, buf, size);
    984  1.14  riastrad 	case HDMI_INFOFRAME_TYPE_SPD:
    985  1.14  riastrad 		return hdmi_spd_infoframe_unpack(&frame->spd, buf, size);
    986  1.14  riastrad 	case HDMI_INFOFRAME_TYPE_VENDOR:
    987  1.14  riastrad 		return hdmi_vendor_infoframe_unpack(&frame->vendor.hdmi, buf,
    988  1.14  riastrad 		    size);
    989  1.14  riastrad 	default:
    990  1.14  riastrad 		return -EINVAL;
    991  1.14  riastrad 	}
    992  1.14  riastrad }
    993  1.14  riastrad 
    994  1.10  riastrad static inline void
    995  1.10  riastrad hdmi_infoframe_log(const char *level, struct device *device,
    996  1.10  riastrad     const union hdmi_infoframe *frame)
    997  1.10  riastrad {
    998  1.10  riastrad 	/* XXX */
    999  1.10  riastrad }
   1000  1.10  riastrad 
   1001   1.1  riastrad #endif	/* _LINUX_HDMI_H_ */
   1002