xref: /netbsd-src/sys/external/bsd/drm2/linux/linux_hdmi.c (revision 740b6d65d0be42fe12408cad0f55cfe8cac1007e)
1*740b6d65Sriastradh /*	$NetBSD: linux_hdmi.c,v 1.10 2022/07/10 13:56:44 riastradh Exp $	*/
2f3393e87Sriastradh 
3f3393e87Sriastradh /*-
4f3393e87Sriastradh  * Copyright (c) 2014 The NetBSD Foundation, Inc.
5f3393e87Sriastradh  * All rights reserved.
6f3393e87Sriastradh  *
7f3393e87Sriastradh  * This code is derived from software contributed to The NetBSD Foundation
8f3393e87Sriastradh  * by Taylor R. Campbell.
9f3393e87Sriastradh  *
10f3393e87Sriastradh  * Redistribution and use in source and binary forms, with or without
11f3393e87Sriastradh  * modification, are permitted provided that the following conditions
12f3393e87Sriastradh  * are met:
13f3393e87Sriastradh  * 1. Redistributions of source code must retain the above copyright
14f3393e87Sriastradh  *    notice, this list of conditions and the following disclaimer.
15f3393e87Sriastradh  * 2. Redistributions in binary form must reproduce the above copyright
16f3393e87Sriastradh  *    notice, this list of conditions and the following disclaimer in the
17f3393e87Sriastradh  *    documentation and/or other materials provided with the distribution.
18f3393e87Sriastradh  *
19f3393e87Sriastradh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20f3393e87Sriastradh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21f3393e87Sriastradh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22f3393e87Sriastradh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23f3393e87Sriastradh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24f3393e87Sriastradh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25f3393e87Sriastradh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26f3393e87Sriastradh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27f3393e87Sriastradh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28f3393e87Sriastradh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29f3393e87Sriastradh  * POSSIBILITY OF SUCH DAMAGE.
30f3393e87Sriastradh  */
31f3393e87Sriastradh 
32f3393e87Sriastradh #include <sys/cdefs.h>
33*740b6d65Sriastradh __KERNEL_RCSID(0, "$NetBSD: linux_hdmi.c,v 1.10 2022/07/10 13:56:44 riastradh Exp $");
34f3393e87Sriastradh 
35f3393e87Sriastradh #include <sys/types.h>
36f3393e87Sriastradh 
37f3393e87Sriastradh #include <sys/device.h>
38f3393e87Sriastradh #include <sys/errno.h>
39f3393e87Sriastradh #include <sys/systm.h>
40f3393e87Sriastradh 
41f3393e87Sriastradh #include <lib/libkern/libkern.h>
42f3393e87Sriastradh 
43f3393e87Sriastradh #include <linux/hdmi.h>
44f3393e87Sriastradh 
45f3393e87Sriastradh /* Infoframe headers */
46f3393e87Sriastradh 
47f3393e87Sriastradh static void
hdmi_infoframe_header_init(struct hdmi_infoframe_header * header,enum hdmi_infoframe_type type,uint8_t vers,uint8_t length)48f3393e87Sriastradh hdmi_infoframe_header_init(struct hdmi_infoframe_header *header,
49f3393e87Sriastradh     enum hdmi_infoframe_type type, uint8_t vers, uint8_t length)
50f3393e87Sriastradh {
51f3393e87Sriastradh 
52f3393e87Sriastradh 	header->type = type;
53f3393e87Sriastradh 	header->version = vers;
54f3393e87Sriastradh 	header->length = length;
55f3393e87Sriastradh }
56f3393e87Sriastradh 
57f3393e87Sriastradh static int
hdmi_infoframe_header_check(const struct hdmi_infoframe_header * header,enum hdmi_infoframe_type type,uint8_t vers,uint8_t length)58f3393e87Sriastradh hdmi_infoframe_header_check(const struct hdmi_infoframe_header *header,
59f3393e87Sriastradh     enum hdmi_infoframe_type type, uint8_t vers, uint8_t length)
60f3393e87Sriastradh {
61f3393e87Sriastradh 
62f3393e87Sriastradh 	if (header->type != type ||
63f3393e87Sriastradh 	    header->version != vers ||
64f3393e87Sriastradh 	    header->length != length)
65f3393e87Sriastradh 		return -EINVAL;
66f3393e87Sriastradh 	return 0;
67f3393e87Sriastradh }
68f3393e87Sriastradh 
69c7520856Sriastradh static ssize_t
hdmi_infoframe_header_pack(const struct hdmi_infoframe_header * header,uint8_t length,void * buf,size_t size)70f3393e87Sriastradh hdmi_infoframe_header_pack(const struct hdmi_infoframe_header *header,
71f3393e87Sriastradh     uint8_t length, void *buf, size_t size)
72f3393e87Sriastradh {
73f3393e87Sriastradh 	uint8_t *const p = buf;
74f3393e87Sriastradh 
75325fdf0fSriastradh 	KASSERT(length >= HDMI_INFOFRAME_HEADER_SIZE);
76325fdf0fSriastradh 
77f3393e87Sriastradh 	if (size < length)
78f3393e87Sriastradh 		return -ENOSPC;
79f3393e87Sriastradh 
80f3393e87Sriastradh 	p[0] = header->type;
81f3393e87Sriastradh 	p[1] = header->version;
82f3393e87Sriastradh 	p[2] = (length - HDMI_INFOFRAME_HEADER_SIZE);
83f3393e87Sriastradh 	p[3] = 0;		/* checksum */
84f3393e87Sriastradh 
85f3393e87Sriastradh 	return HDMI_INFOFRAME_HEADER_SIZE;
86f3393e87Sriastradh }
87f3393e87Sriastradh 
88f3393e87Sriastradh static uint8_t
hdmi_infoframe_checksum(const void * buf,size_t length)89f3393e87Sriastradh hdmi_infoframe_checksum(const void *buf, size_t length)
90f3393e87Sriastradh {
91f3393e87Sriastradh 	const uint8_t *p = buf;
92f3393e87Sriastradh 	uint8_t checksum = 0;
93f3393e87Sriastradh 
94f3393e87Sriastradh 	while (length--)
95f3393e87Sriastradh 		checksum += *p++;
96f3393e87Sriastradh 
97f3393e87Sriastradh 	return 256 - checksum;
98f3393e87Sriastradh }
99f3393e87Sriastradh 
100f3393e87Sriastradh static int
hdmi_infoframe_header_unpack(struct hdmi_infoframe_header * header,const void * buf,size_t size)101f3393e87Sriastradh hdmi_infoframe_header_unpack(struct hdmi_infoframe_header *header,
102f3393e87Sriastradh     const void *buf, size_t size)
103f3393e87Sriastradh {
104f3393e87Sriastradh 	const uint8_t *const p = buf;
105f3393e87Sriastradh 
106f3393e87Sriastradh 	if (size < HDMI_INFOFRAME_HEADER_SIZE)
107f3393e87Sriastradh 		return -EINVAL;
108f3393e87Sriastradh 	if (p[2] > size - HDMI_INFOFRAME_HEADER_SIZE)
109f3393e87Sriastradh 		return -EINVAL;
110f3393e87Sriastradh 	if (hdmi_infoframe_checksum(buf, p[2] + HDMI_INFOFRAME_HEADER_SIZE))
111f3393e87Sriastradh 		return -EINVAL;
112f3393e87Sriastradh 
113f3393e87Sriastradh 	hdmi_infoframe_header_init(header, p[0], p[1], p[2]);
114add6c02dSriastradh 	return 0;
115f3393e87Sriastradh }
116f3393e87Sriastradh 
117f3393e87Sriastradh static void
hdmi_infoframe_set_checksum(void * buf,size_t length)118f3393e87Sriastradh hdmi_infoframe_set_checksum(void *buf, size_t length)
119f3393e87Sriastradh {
120f3393e87Sriastradh 	uint8_t *p = buf;
121f3393e87Sriastradh 
122f3393e87Sriastradh 	p[3] = hdmi_infoframe_checksum(buf, length);
123f3393e87Sriastradh }
124f3393e87Sriastradh 
125f3393e87Sriastradh /* Audio infoframes */
126f3393e87Sriastradh 
127f3393e87Sriastradh int
hdmi_audio_infoframe_init(struct hdmi_audio_infoframe * frame)128f3393e87Sriastradh hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
129f3393e87Sriastradh {
130f3393e87Sriastradh 	static const struct hdmi_audio_infoframe zero_frame;
131f3393e87Sriastradh 
132f3393e87Sriastradh 	*frame = zero_frame;
133f3393e87Sriastradh 
134f3393e87Sriastradh 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AUDIO,
135f3393e87Sriastradh 	    1, HDMI_AUDIO_INFOFRAME_SIZE);
136f3393e87Sriastradh 
137f3393e87Sriastradh 	return 0;
138f3393e87Sriastradh }
139f3393e87Sriastradh 
140f3393e87Sriastradh ssize_t
hdmi_audio_infoframe_pack(const struct hdmi_audio_infoframe * frame,void * buf,size_t size)141f3393e87Sriastradh hdmi_audio_infoframe_pack(const struct hdmi_audio_infoframe *frame, void *buf,
142f3393e87Sriastradh     size_t size)
143f3393e87Sriastradh {
144f3393e87Sriastradh 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
145f3393e87Sriastradh 	    HDMI_AUDIO_INFOFRAME_SIZE;
146f3393e87Sriastradh 	uint8_t channels = 0;
147f3393e87Sriastradh 	uint8_t *p = buf;
148f3393e87Sriastradh 	int ret;
149f3393e87Sriastradh 
150f3393e87Sriastradh 	KASSERT(frame->header.length == HDMI_AUDIO_INFOFRAME_SIZE);
151f3393e87Sriastradh 
152f3393e87Sriastradh 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
153f3393e87Sriastradh 	if (ret < 0)
154f3393e87Sriastradh 		return ret;
155f3393e87Sriastradh 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
156f3393e87Sriastradh 	p += HDMI_INFOFRAME_HEADER_SIZE;
157f3393e87Sriastradh 	size -= HDMI_INFOFRAME_HEADER_SIZE;
158f3393e87Sriastradh 
159f3393e87Sriastradh 	if (frame->channels >= 2)
160f3393e87Sriastradh 		channels = frame->channels - 1;
161f3393e87Sriastradh 
162f3393e87Sriastradh 	p[0] = __SHIFTIN(frame->coding_type, __BITS(7,4));
163f3393e87Sriastradh 	p[0] |= __SHIFTIN(channels, __BITS(2,0));
164f3393e87Sriastradh 
165f3393e87Sriastradh 	p[1] = __SHIFTIN(frame->sample_frequency, __BITS(4,2));
166f3393e87Sriastradh 	p[1] |= __SHIFTIN(frame->sample_size, __BITS(1,0));
167f3393e87Sriastradh 
168f3393e87Sriastradh 	p[2] = __SHIFTIN(frame->coding_type_ext, __BITS(5,0));
169f3393e87Sriastradh 
170f3393e87Sriastradh 	p[3] = __SHIFTIN(frame->level_shift_value, __BITS(6,3));
171f3393e87Sriastradh 
172f3393e87Sriastradh 	p[4] = __SHIFTIN(frame->downmix_inhibit? 1 : 0, __BIT(7));
173f3393e87Sriastradh 
174f3393e87Sriastradh 	/* PB6 to PB10 are reserved */
175f3393e87Sriastradh 	p[5] = 0;
176f3393e87Sriastradh 	p[6] = 0;
177f3393e87Sriastradh 	p[7] = 0;
178f3393e87Sriastradh 	p[8] = 0;
179f3393e87Sriastradh 	p[9] = 0;
180f3393e87Sriastradh 
181f3393e87Sriastradh 	CTASSERT(HDMI_AUDIO_INFOFRAME_SIZE == 10);
182f3393e87Sriastradh 
183f3393e87Sriastradh 	hdmi_infoframe_set_checksum(buf, length);
184f3393e87Sriastradh 
185f3393e87Sriastradh 	return length;
186f3393e87Sriastradh }
187f3393e87Sriastradh 
1884f8e99e7Sriastradh static int
hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe * frame,const void * buf,size_t size)189f3393e87Sriastradh hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
190f3393e87Sriastradh     const void *buf, size_t size)
191f3393e87Sriastradh {
192f3393e87Sriastradh 	const uint8_t *p = buf;
193f3393e87Sriastradh 	int ret;
194f3393e87Sriastradh 
195f3393e87Sriastradh 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
196f3393e87Sriastradh 	if (ret)
197f3393e87Sriastradh 		return ret;
198f3393e87Sriastradh 	if (frame->header.length != HDMI_AUDIO_INFOFRAME_SIZE)
199f3393e87Sriastradh 		return -EINVAL;
200f3393e87Sriastradh 	p += HDMI_INFOFRAME_HEADER_SIZE;
201f3393e87Sriastradh 	size -= HDMI_INFOFRAME_HEADER_SIZE;
202f3393e87Sriastradh 
203f3393e87Sriastradh 	frame->coding_type = __SHIFTOUT(p[0], __BITS(7,4));
204f3393e87Sriastradh 	frame->channels = __SHIFTOUT(p[0], __BITS(2,0));
205f3393e87Sriastradh 
206f3393e87Sriastradh 	frame->sample_frequency = __SHIFTOUT(p[1], __BITS(4,2));
207f3393e87Sriastradh 	frame->sample_size = __SHIFTOUT(p[1], __BITS(1,0));
208f3393e87Sriastradh 
209f3393e87Sriastradh 	frame->coding_type_ext = __SHIFTOUT(p[2], __BITS(5,0));
210f3393e87Sriastradh 
211f3393e87Sriastradh 	frame->level_shift_value = __SHIFTOUT(p[3], __BITS(6,3));
212f3393e87Sriastradh 
213f3393e87Sriastradh 	frame->downmix_inhibit = __SHIFTOUT(p[4], __BIT(7));
214f3393e87Sriastradh 
215f3393e87Sriastradh 	return 0;
216f3393e87Sriastradh }
217f3393e87Sriastradh 
218f3393e87Sriastradh /* AVI infoframes */
219f3393e87Sriastradh 
220f3393e87Sriastradh int
hdmi_avi_infoframe_init(struct hdmi_avi_infoframe * frame)221f3393e87Sriastradh hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
222f3393e87Sriastradh {
223f3393e87Sriastradh 	static const struct hdmi_avi_infoframe zero_frame;
224f3393e87Sriastradh 
225f3393e87Sriastradh 	*frame = zero_frame;
226f3393e87Sriastradh 
227f3393e87Sriastradh 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_AVI, 2,
228f3393e87Sriastradh 	    HDMI_AVI_INFOFRAME_SIZE);
229f3393e87Sriastradh 
230f3393e87Sriastradh 	return 0;
231f3393e87Sriastradh }
232f3393e87Sriastradh 
233f3393e87Sriastradh int
hdmi_avi_infoframe_check(const struct hdmi_avi_infoframe * frame)234f3393e87Sriastradh hdmi_avi_infoframe_check(const struct hdmi_avi_infoframe *frame)
235f3393e87Sriastradh {
236f3393e87Sriastradh 	int ret;
237f3393e87Sriastradh 
238f3393e87Sriastradh 	ret = hdmi_infoframe_header_check(&frame->header,
239f3393e87Sriastradh 	    HDMI_INFOFRAME_TYPE_AVI, 2, HDMI_AVI_INFOFRAME_SIZE);
240f3393e87Sriastradh 	if (ret)
241f3393e87Sriastradh 		return ret;
242f3393e87Sriastradh 
243f3393e87Sriastradh 	return 0;
244f3393e87Sriastradh }
245f3393e87Sriastradh 
246f3393e87Sriastradh ssize_t
hdmi_avi_infoframe_pack(const struct hdmi_avi_infoframe * frame,void * buf,size_t size)247f3393e87Sriastradh hdmi_avi_infoframe_pack(const struct hdmi_avi_infoframe *frame, void *buf,
248f3393e87Sriastradh     size_t size)
249f3393e87Sriastradh {
250f3393e87Sriastradh 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
251f3393e87Sriastradh 	    HDMI_AVI_INFOFRAME_SIZE;
252f3393e87Sriastradh 	uint8_t *p = buf;
253f3393e87Sriastradh 	int ret;
254f3393e87Sriastradh 
255f3393e87Sriastradh 	KASSERT(frame->header.length == HDMI_AVI_INFOFRAME_SIZE);
256f3393e87Sriastradh 
257f3393e87Sriastradh 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
258f3393e87Sriastradh 	if (ret < 0)
259f3393e87Sriastradh 		return ret;
260f3393e87Sriastradh 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
261f3393e87Sriastradh 	p += HDMI_INFOFRAME_HEADER_SIZE;
262f3393e87Sriastradh 	size -= HDMI_INFOFRAME_HEADER_SIZE;
263f3393e87Sriastradh 
264f3393e87Sriastradh 	p[0] = __SHIFTIN(frame->colorspace, __BITS(6,5));
265f3393e87Sriastradh 	p[0] |= __SHIFTIN(frame->active_aspect & 0xf? 1 : 0, __BIT(4));
266f3393e87Sriastradh 	p[0] |= __SHIFTIN(frame->top_bar || frame->bottom_bar, __BIT(3));
267f3393e87Sriastradh 	p[0] |= __SHIFTIN(frame->left_bar || frame->right_bar, __BIT(2));
268f3393e87Sriastradh 	p[0] |= __SHIFTIN(frame->scan_mode, __BITS(1,0));
269f3393e87Sriastradh 
270f3393e87Sriastradh 	p[1] = __SHIFTIN(frame->colorimetry, __BITS(7,6));
271f3393e87Sriastradh 	p[1] |= __SHIFTIN(frame->picture_aspect, __BITS(5,4));
272f3393e87Sriastradh 	p[1] |= __SHIFTIN(frame->active_aspect, __BITS(3,0));
273f3393e87Sriastradh 
274f3393e87Sriastradh 	p[2] = __SHIFTIN(frame->itc? 1 : 0, __BIT(7));
275f3393e87Sriastradh 	p[2] |= __SHIFTIN(frame->extended_colorimetry, __BITS(6,4));
276f3393e87Sriastradh 	p[2] |= __SHIFTIN(frame->quantization_range, __BITS(3,2));
277f3393e87Sriastradh 	p[2] |= __SHIFTIN(frame->nups, __BITS(1,0));
278f3393e87Sriastradh 
279f3393e87Sriastradh 	p[3] = frame->video_code;
280f3393e87Sriastradh 
281f3393e87Sriastradh 	p[4] = __SHIFTIN(frame->ycc_quantization_range, __BITS(7,6));
282f3393e87Sriastradh 	p[4] |= __SHIFTIN(frame->content_type, __BITS(5,4));
283f3393e87Sriastradh 	p[4] |= __SHIFTIN(frame->pixel_repeat, __BITS(3,0));
284f3393e87Sriastradh 
285f3393e87Sriastradh 	le16enc(&p[5], frame->top_bar);
286f3393e87Sriastradh 	le16enc(&p[7], frame->bottom_bar);
287f3393e87Sriastradh 	le16enc(&p[9], frame->left_bar);
288f3393e87Sriastradh 	le16enc(&p[11], frame->right_bar);
289f3393e87Sriastradh 	CTASSERT(HDMI_AVI_INFOFRAME_SIZE == 13);
290f3393e87Sriastradh 
291f3393e87Sriastradh 	hdmi_infoframe_set_checksum(buf, length);
292f3393e87Sriastradh 
293f3393e87Sriastradh 	return length;
294f3393e87Sriastradh }
295f3393e87Sriastradh 
2964f8e99e7Sriastradh static int
hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe * frame,const void * buf,size_t size)297f3393e87Sriastradh hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame, const void *buf,
298f3393e87Sriastradh     size_t size)
299f3393e87Sriastradh {
300f3393e87Sriastradh 	const uint8_t *p = buf;
301f3393e87Sriastradh 	int ret;
302f3393e87Sriastradh 
303f3393e87Sriastradh 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
304f3393e87Sriastradh 	if (ret)
305f3393e87Sriastradh 		return ret;
306f3393e87Sriastradh 	if (frame->header.length != HDMI_AVI_INFOFRAME_SIZE)
307f3393e87Sriastradh 		return -EINVAL;
308f3393e87Sriastradh 	p += HDMI_INFOFRAME_HEADER_SIZE;
309f3393e87Sriastradh 	size -= HDMI_INFOFRAME_HEADER_SIZE;
310f3393e87Sriastradh 
311f3393e87Sriastradh 	frame->colorspace = __SHIFTOUT(p[0], __BITS(6,5));
312f3393e87Sriastradh 	frame->scan_mode = __SHIFTOUT(p[0], __BITS(1,0));
313f3393e87Sriastradh 
314f3393e87Sriastradh 	frame->colorimetry = __SHIFTOUT(p[1], __BITS(7,6));
315f3393e87Sriastradh 	frame->picture_aspect = __SHIFTOUT(p[1], __BITS(5,4));
316f3393e87Sriastradh 	if (p[0] & __BIT(4))
317f3393e87Sriastradh 		frame->active_aspect = __SHIFTOUT(p[1], __BITS(3,0));
318f3393e87Sriastradh 
319f3393e87Sriastradh 	frame->itc = __SHIFTOUT(p[2], __BIT(7));
320f3393e87Sriastradh 	frame->extended_colorimetry = __SHIFTOUT(p[2], __BITS(6,4));
321f3393e87Sriastradh 	frame->quantization_range = __SHIFTOUT(p[2], __BITS(3,2));
322f3393e87Sriastradh 	frame->nups = __SHIFTOUT(p[2], __BITS(1,0));
323f3393e87Sriastradh 
324f3393e87Sriastradh 	frame->video_code = p[3];
325f3393e87Sriastradh 
326f3393e87Sriastradh 	frame->ycc_quantization_range = __SHIFTOUT(p[4], __BITS(7,6));
327f3393e87Sriastradh 	frame->content_type = __SHIFTOUT(p[4], __BITS(5,4));
328f3393e87Sriastradh 	frame->pixel_repeat = __SHIFTOUT(p[4], __BITS(3,0));
329f3393e87Sriastradh 
330f3393e87Sriastradh 	if (p[0] & __BIT(3)) {
331f3393e87Sriastradh 		frame->top_bar = le16dec(&p[5]);
332f3393e87Sriastradh 		frame->bottom_bar = le16dec(&p[7]);
333f3393e87Sriastradh 	}
334f3393e87Sriastradh 	if (p[0] & __BIT(2)) {
335f3393e87Sriastradh 		frame->left_bar = le16dec(&p[9]);
336f3393e87Sriastradh 		frame->right_bar = le16dec(&p[11]);
337f3393e87Sriastradh 	}
338f3393e87Sriastradh 
339f3393e87Sriastradh 	return 0;
340f3393e87Sriastradh }
341f3393e87Sriastradh 
342f3393e87Sriastradh /* DRM infoframes */
343f3393e87Sriastradh 
344f3393e87Sriastradh int
hdmi_drm_infoframe_init(struct hdmi_drm_infoframe * frame)345f3393e87Sriastradh hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame)
346f3393e87Sriastradh {
347f3393e87Sriastradh 	static const struct hdmi_drm_infoframe zero_frame;
348f3393e87Sriastradh 
349f3393e87Sriastradh 	*frame = zero_frame;
350f3393e87Sriastradh 
351f3393e87Sriastradh 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_DRM,
352f3393e87Sriastradh 	    1, HDMI_DRM_INFOFRAME_SIZE);
353f3393e87Sriastradh 
354f3393e87Sriastradh 	return 0;
355f3393e87Sriastradh }
356f3393e87Sriastradh 
357f3393e87Sriastradh int
hdmi_drm_infoframe_check(const struct hdmi_drm_infoframe * frame)358f3393e87Sriastradh hdmi_drm_infoframe_check(const struct hdmi_drm_infoframe *frame)
359f3393e87Sriastradh {
360f3393e87Sriastradh 	int ret;
361f3393e87Sriastradh 
362f3393e87Sriastradh 	ret = hdmi_infoframe_header_check(&frame->header,
363f3393e87Sriastradh 	    HDMI_INFOFRAME_TYPE_DRM, 1, HDMI_DRM_INFOFRAME_SIZE);
364f3393e87Sriastradh 	if (ret)
365f3393e87Sriastradh 		return ret;
366f3393e87Sriastradh 
367f3393e87Sriastradh 	return 0;
368f3393e87Sriastradh }
369f3393e87Sriastradh 
__strong_alias(linux_hdmi_drm_infoframe_pack_only,linux_hdmi_drm_infoframe_pack)370f3393e87Sriastradh __strong_alias(linux_hdmi_drm_infoframe_pack_only,linux_hdmi_drm_infoframe_pack) /* XXX */
371f3393e87Sriastradh 
372c7520856Sriastradh ssize_t
373f3393e87Sriastradh hdmi_drm_infoframe_pack(const struct hdmi_drm_infoframe *frame,
374f3393e87Sriastradh     void *buf, size_t size)
375f3393e87Sriastradh {
376f3393e87Sriastradh 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
377f3393e87Sriastradh 	    HDMI_DRM_INFOFRAME_SIZE;
378f3393e87Sriastradh 	uint8_t *p = buf;
379f3393e87Sriastradh 	unsigned i;
380f3393e87Sriastradh 	int ret;
381f3393e87Sriastradh 
382f3393e87Sriastradh 	KASSERT(frame->header.length == HDMI_DRM_INFOFRAME_SIZE);
383f3393e87Sriastradh 
384f3393e87Sriastradh 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
385f3393e87Sriastradh 	if (ret < 0)
386f3393e87Sriastradh 		return ret;
387f3393e87Sriastradh 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
388f3393e87Sriastradh 	p += HDMI_INFOFRAME_HEADER_SIZE;
389f3393e87Sriastradh 	size -= HDMI_INFOFRAME_HEADER_SIZE;
390f3393e87Sriastradh 
391f3393e87Sriastradh 	p[0] = frame->eotf;
392f3393e87Sriastradh 	p[1] = frame->metadata_type;
393f3393e87Sriastradh 	for (i = 0; i < __arraycount(frame->display_primaries); i++) {
394f3393e87Sriastradh 		le16enc(&p[2 + 4*i], frame->display_primaries[i].x);
395f3393e87Sriastradh 		le16enc(&p[2 + 4*i + 2], frame->display_primaries[i].y);
396f3393e87Sriastradh 	}
397f3393e87Sriastradh 	le16enc(&p[14], frame->white_point.x);
398f3393e87Sriastradh 	le16enc(&p[16], frame->white_point.y);
399f3393e87Sriastradh 	le16enc(&p[18], frame->min_display_mastering_luminance);
400f3393e87Sriastradh 	le16enc(&p[20], frame->max_display_mastering_luminance);
401f3393e87Sriastradh 	le16enc(&p[22], frame->max_cll);
402f3393e87Sriastradh 	le16enc(&p[24], frame->max_fall);
403f3393e87Sriastradh 	CTASSERT(HDMI_DRM_INFOFRAME_SIZE == 26);
404f3393e87Sriastradh 
405f3393e87Sriastradh 	hdmi_infoframe_set_checksum(buf, length);
406f3393e87Sriastradh 
407f3393e87Sriastradh 	return length;
408f3393e87Sriastradh }
409f3393e87Sriastradh 
4104f8e99e7Sriastradh static int
hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe * frame,const void * buf,size_t size)411f3393e87Sriastradh hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe *frame, const void *buf,
412f3393e87Sriastradh     size_t size)
413f3393e87Sriastradh {
414f3393e87Sriastradh 	const uint8_t *p = buf;
415f3393e87Sriastradh 	unsigned i;
416f3393e87Sriastradh 	int ret;
417f3393e87Sriastradh 
418f3393e87Sriastradh 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
419f3393e87Sriastradh 	if (ret)
420f3393e87Sriastradh 		return ret;
421f3393e87Sriastradh 	if (frame->header.length != HDMI_DRM_INFOFRAME_SIZE)
422f3393e87Sriastradh 		return -EINVAL;
423f3393e87Sriastradh 	p += HDMI_INFOFRAME_HEADER_SIZE;
424f3393e87Sriastradh 	size -= HDMI_INFOFRAME_HEADER_SIZE;
425f3393e87Sriastradh 
426f3393e87Sriastradh 	frame->eotf = p[0];
427f3393e87Sriastradh 	frame->metadata_type = p[1];
428f3393e87Sriastradh 	for (i = 0; i < __arraycount(frame->display_primaries); i++) {
429f3393e87Sriastradh 		frame->display_primaries[i].x = le16dec(&p[2 + 4*i]);
430f3393e87Sriastradh 		frame->display_primaries[i].y = le16dec(&p[2 + 4*i + 2]);
431f3393e87Sriastradh 	}
432f3393e87Sriastradh 	frame->white_point.x = le16dec(&p[14]);
433f3393e87Sriastradh 	frame->white_point.y = le16dec(&p[16]);
434f3393e87Sriastradh 	frame->min_display_mastering_luminance = le16dec(&p[18]);
435f3393e87Sriastradh 	frame->max_display_mastering_luminance = le16dec(&p[20]);
436f3393e87Sriastradh 	frame->max_cll = le16dec(&p[22]);
437f3393e87Sriastradh 	frame->max_fall = le16dec(&p[24]);
438f3393e87Sriastradh 
439f3393e87Sriastradh 	return 0;
440f3393e87Sriastradh }
441f3393e87Sriastradh 
442f3393e87Sriastradh /* SPD infoframes */
443f3393e87Sriastradh 
444f3393e87Sriastradh int
hdmi_spd_infoframe_init(struct hdmi_spd_infoframe * frame,const char * vendor,const char * product)445f3393e87Sriastradh hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, const char *vendor,
446f3393e87Sriastradh     const char *product)
447f3393e87Sriastradh {
448f3393e87Sriastradh 	static const struct hdmi_spd_infoframe zero_frame;
449f3393e87Sriastradh 
450f3393e87Sriastradh 	*frame = zero_frame;
451f3393e87Sriastradh 
452f3393e87Sriastradh 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_SPD,
453f3393e87Sriastradh 	    1, HDMI_SPD_INFOFRAME_SIZE);
454f3393e87Sriastradh 
455f3393e87Sriastradh 	strncpy(frame->vendor, vendor, sizeof(frame->vendor));
456f3393e87Sriastradh 	strncpy(frame->product, product, sizeof(frame->product));
457f3393e87Sriastradh 
458f3393e87Sriastradh 	return 0;
459f3393e87Sriastradh }
460f3393e87Sriastradh 
461f3393e87Sriastradh int
hdmi_spd_infoframe_check(const struct hdmi_spd_infoframe * frame)462f3393e87Sriastradh hdmi_spd_infoframe_check(const struct hdmi_spd_infoframe *frame)
463f3393e87Sriastradh {
464f3393e87Sriastradh 	int ret;
465f3393e87Sriastradh 
466f3393e87Sriastradh 	ret = hdmi_infoframe_header_check(&frame->header,
467f3393e87Sriastradh 	    HDMI_INFOFRAME_TYPE_SPD, 1, HDMI_SPD_INFOFRAME_SIZE);
468f3393e87Sriastradh 	if (ret)
469f3393e87Sriastradh 		return ret;
470f3393e87Sriastradh 
471f3393e87Sriastradh 	return 0;
472f3393e87Sriastradh }
473f3393e87Sriastradh 
474f3393e87Sriastradh ssize_t
hdmi_spd_infoframe_pack(const struct hdmi_spd_infoframe * frame,void * buf,size_t size)475f3393e87Sriastradh hdmi_spd_infoframe_pack(const struct hdmi_spd_infoframe *frame, void *buf,
476f3393e87Sriastradh     size_t size)
477f3393e87Sriastradh {
478f3393e87Sriastradh 	const size_t length = HDMI_INFOFRAME_HEADER_SIZE +
479f3393e87Sriastradh 	    HDMI_SPD_INFOFRAME_SIZE;
480f3393e87Sriastradh 	uint8_t *p = buf;
481f3393e87Sriastradh 	int ret;
482f3393e87Sriastradh 
483f3393e87Sriastradh 	KASSERT(frame->header.length == HDMI_SPD_INFOFRAME_SIZE);
484f3393e87Sriastradh 
485f3393e87Sriastradh 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
486f3393e87Sriastradh 	if (ret < 0)
487f3393e87Sriastradh 		return ret;
488f3393e87Sriastradh 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
489f3393e87Sriastradh 	p += HDMI_INFOFRAME_HEADER_SIZE;
490f3393e87Sriastradh 	size -= HDMI_INFOFRAME_HEADER_SIZE;
491f3393e87Sriastradh 
492f3393e87Sriastradh 	memcpy(&p[0], frame->vendor, 8);
493f3393e87Sriastradh 	memcpy(&p[8], frame->product, 16);
494f3393e87Sriastradh 	p[24] = frame->sdi;
495f3393e87Sriastradh 	CTASSERT(HDMI_SPD_INFOFRAME_SIZE == 25);
496f3393e87Sriastradh 
497f3393e87Sriastradh 	hdmi_infoframe_set_checksum(buf, length);
498f3393e87Sriastradh 
499f3393e87Sriastradh 	return length;
500f3393e87Sriastradh }
501f3393e87Sriastradh 
5024f8e99e7Sriastradh static int
hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe * frame,const void * buf,size_t size)503f3393e87Sriastradh hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame, const void *buf,
504f3393e87Sriastradh     size_t size)
505f3393e87Sriastradh {
506f3393e87Sriastradh 	const uint8_t *p = buf;
507f3393e87Sriastradh 	int ret;
508f3393e87Sriastradh 
509f3393e87Sriastradh 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
510f3393e87Sriastradh 	if (ret)
511f3393e87Sriastradh 		return ret;
512f3393e87Sriastradh 	if (frame->header.length != HDMI_SPD_INFOFRAME_SIZE)
513f3393e87Sriastradh 		return -EINVAL;
514f3393e87Sriastradh 	p += HDMI_INFOFRAME_HEADER_SIZE;
515f3393e87Sriastradh 	size -= HDMI_INFOFRAME_HEADER_SIZE;
516f3393e87Sriastradh 
517f3393e87Sriastradh 	memcpy(frame->vendor, &p[0], 8);
518*740b6d65Sriastradh 	memcpy(frame->product, &p[8], 16);
519f3393e87Sriastradh 	frame->sdi = p[24];
520f3393e87Sriastradh 
521f3393e87Sriastradh 	return 0;
522f3393e87Sriastradh }
523f3393e87Sriastradh 
524f3393e87Sriastradh /* Vendor infoframes */
525f3393e87Sriastradh 
526f3393e87Sriastradh int
hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe * frame)527f3393e87Sriastradh hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
528f3393e87Sriastradh {
529f3393e87Sriastradh 	static const struct hdmi_vendor_infoframe zero_frame;
530f3393e87Sriastradh 
531f3393e87Sriastradh 	*frame = zero_frame;
532f3393e87Sriastradh 
533f3393e87Sriastradh 	hdmi_infoframe_header_init(&frame->header, HDMI_INFOFRAME_TYPE_VENDOR,
534f3393e87Sriastradh 	    1, 0 /* depends on s3d_struct */);
535f3393e87Sriastradh 
536f3393e87Sriastradh 	frame->oui = HDMI_IEEE_OUI;
537f3393e87Sriastradh 	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
538f3393e87Sriastradh 
539f3393e87Sriastradh 	return 0;
540f3393e87Sriastradh }
541f3393e87Sriastradh 
5424f8e99e7Sriastradh static size_t
hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe * frame)543f3393e87Sriastradh hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame)
544f3393e87Sriastradh {
545f3393e87Sriastradh 
546f3393e87Sriastradh 	if (frame->vic) {
547f3393e87Sriastradh 		return 5;
548f3393e87Sriastradh 	} else if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
549f3393e87Sriastradh 		if (frame->s3d_struct < HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
550f3393e87Sriastradh 			return 5;
551f3393e87Sriastradh 		else
552f3393e87Sriastradh 			return 6;
553f3393e87Sriastradh 	} else {
554f3393e87Sriastradh 		return 4;
555f3393e87Sriastradh 	}
556f3393e87Sriastradh }
557f3393e87Sriastradh 
558f3393e87Sriastradh int
hdmi_vendor_infoframe_check(const struct hdmi_vendor_infoframe * frame)559f3393e87Sriastradh hdmi_vendor_infoframe_check(const struct hdmi_vendor_infoframe *frame)
560f3393e87Sriastradh {
561f3393e87Sriastradh 
562f3393e87Sriastradh 	if (frame->header.type != HDMI_INFOFRAME_TYPE_VENDOR ||
563f3393e87Sriastradh 	    frame->header.version != 1)
564f3393e87Sriastradh 		return -EINVAL;
565f3393e87Sriastradh 	/* frame->header.length not used when packing */
566f3393e87Sriastradh 
567f3393e87Sriastradh 	/* At most one may be supplied.  */
568f3393e87Sriastradh 	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
569f3393e87Sriastradh 		return -EINVAL;
570f3393e87Sriastradh 
571f3393e87Sriastradh 	return 0;
572f3393e87Sriastradh }
573f3393e87Sriastradh 
574c7520856Sriastradh ssize_t
hdmi_vendor_infoframe_pack(const struct hdmi_vendor_infoframe * frame,void * buf,size_t size)575f3393e87Sriastradh hdmi_vendor_infoframe_pack(const struct hdmi_vendor_infoframe *frame,
576f3393e87Sriastradh     void *buf, size_t size)
577f3393e87Sriastradh {
578f3393e87Sriastradh 	uint8_t *p = buf;
579f3393e87Sriastradh 	size_t length;
580f3393e87Sriastradh 	int ret;
581f3393e87Sriastradh 
582f3393e87Sriastradh 	/* At most one may be supplied.  */
583f3393e87Sriastradh 	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
584f3393e87Sriastradh 		return -EINVAL;
585f3393e87Sriastradh 
586f3393e87Sriastradh 	length = HDMI_INFOFRAME_HEADER_SIZE;
587f3393e87Sriastradh 	length += hdmi_vendor_infoframe_length(frame);
588f3393e87Sriastradh 
589f3393e87Sriastradh 	ret = hdmi_infoframe_header_pack(&frame->header, length, p, size);
590f3393e87Sriastradh 	if (ret < 0)
591f3393e87Sriastradh 		return ret;
592f3393e87Sriastradh 	KASSERT(ret == HDMI_INFOFRAME_HEADER_SIZE);
593f3393e87Sriastradh 	p += HDMI_INFOFRAME_HEADER_SIZE;
594f3393e87Sriastradh 	size -= HDMI_INFOFRAME_HEADER_SIZE;
595f3393e87Sriastradh 
596f3393e87Sriastradh 	p[0] = 0x03;
597f3393e87Sriastradh 	p[1] = 0x0c;
598f3393e87Sriastradh 	p[2] = 0x00;
599f3393e87Sriastradh 
600f3393e87Sriastradh 	if (frame->vic) {
601f3393e87Sriastradh 		p[3] = __SHIFTIN(0x1, __BITS(6,5));
602f3393e87Sriastradh 		p[4] = frame->vic;
603f3393e87Sriastradh 	} else if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
604f3393e87Sriastradh 		p[3] = __SHIFTIN(0x2, __BITS(6,5));
605f3393e87Sriastradh 		p[4] = __SHIFTIN(frame->s3d_struct, __BITS(7,4));
606f3393e87Sriastradh 		if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
607f3393e87Sriastradh 			p[5] = __SHIFTIN(frame->s3d_ext_data, __BITS(7,4));
608f3393e87Sriastradh 	} else {
609f3393e87Sriastradh 		p[3] = __SHIFTIN(0x0, __BITS(6,5));
610f3393e87Sriastradh 	}
611f3393e87Sriastradh 
612f3393e87Sriastradh 	hdmi_infoframe_set_checksum(buf, length);
613f3393e87Sriastradh 
614f3393e87Sriastradh 	return length;
615f3393e87Sriastradh }
616f3393e87Sriastradh 
6174f8e99e7Sriastradh static int
hdmi_vendor_infoframe_unpack(struct hdmi_vendor_infoframe * frame,const void * buf,size_t size)618f3393e87Sriastradh hdmi_vendor_infoframe_unpack(struct hdmi_vendor_infoframe *frame,
619f3393e87Sriastradh     const void *buf, size_t size)
620f3393e87Sriastradh {
621f3393e87Sriastradh 	const uint8_t *p = buf;
622f3393e87Sriastradh 	int ret;
623f3393e87Sriastradh 
624f3393e87Sriastradh 	ret = hdmi_infoframe_header_unpack(&frame->header, p, size);
625f3393e87Sriastradh 	if (ret)
626f3393e87Sriastradh 		return ret;
627f3393e87Sriastradh 	if (frame->header.length < 4)
628f3393e87Sriastradh 		return -EINVAL;
629f3393e87Sriastradh 	p += HDMI_INFOFRAME_HEADER_SIZE;
630f3393e87Sriastradh 	size -= HDMI_INFOFRAME_HEADER_SIZE;
631f3393e87Sriastradh 
632f3393e87Sriastradh 	if (p[0] != 0x03 || p[1] != 0x0c || p[2] != 0x00)
633f3393e87Sriastradh 		return -EINVAL;
634f3393e87Sriastradh 
635f3393e87Sriastradh 	switch (__SHIFTOUT(p[3], __BITS(6,5))) {
636f3393e87Sriastradh 	case 0x0:
637f3393e87Sriastradh 		if (frame->header.length != 4)
638f3393e87Sriastradh 			return -EINVAL;
639f3393e87Sriastradh 		break;
640f3393e87Sriastradh 	case 0x1:
641f3393e87Sriastradh 		if (frame->header.length != 5)
642f3393e87Sriastradh 			return -EINVAL;
643f3393e87Sriastradh 		frame->vic = p[4];
644f3393e87Sriastradh 		break;
645f3393e87Sriastradh 	case 0x2:
646f3393e87Sriastradh 		if (frame->header.length < 5)
647f3393e87Sriastradh 			return -EINVAL;
648f3393e87Sriastradh 		frame->s3d_struct = __SHIFTOUT(p[4], __BITS(7,4));
649f3393e87Sriastradh 		if (frame->s3d_struct < HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
650f3393e87Sriastradh 			if (frame->header.length != 5)
651f3393e87Sriastradh 				return -EINVAL;
652f3393e87Sriastradh 		} else {
653f3393e87Sriastradh 			if (frame->header.length != 6)
654f3393e87Sriastradh 				return -EINVAL;
655f3393e87Sriastradh 			frame->s3d_ext_data = __SHIFTOUT(p[5], __BITS(7,4));
656f3393e87Sriastradh 		}
657f3393e87Sriastradh 		break;
658f3393e87Sriastradh 	default:
659f3393e87Sriastradh 		return -EINVAL;
660f3393e87Sriastradh 	}
661f3393e87Sriastradh 
662f3393e87Sriastradh 	return 0;
663f3393e87Sriastradh }
664f3393e87Sriastradh 
665f3393e87Sriastradh /* union infoframe */
666f3393e87Sriastradh 
__strong_alias(linux_hdmi_infoframe_pack_only,linux_hdmi_infoframe_pack)667f3393e87Sriastradh __strong_alias(linux_hdmi_infoframe_pack_only,linux_hdmi_infoframe_pack) /* XXX */
668f3393e87Sriastradh 
669f3393e87Sriastradh ssize_t
670f3393e87Sriastradh hdmi_infoframe_pack(const union hdmi_infoframe *frame, void *buf, size_t size)
671f3393e87Sriastradh {
672f3393e87Sriastradh 
673f3393e87Sriastradh 	switch (frame->any.type) {
674f3393e87Sriastradh 	case HDMI_INFOFRAME_TYPE_VENDOR:
675f3393e87Sriastradh 		return hdmi_vendor_infoframe_pack(&frame->vendor.hdmi, buf,
676f3393e87Sriastradh 		    size);
677d6e94fe5Sriastradh 	case HDMI_INFOFRAME_TYPE_AVI:
678d6e94fe5Sriastradh 		return hdmi_avi_infoframe_pack(&frame->avi, buf, size);
679d6e94fe5Sriastradh 	case HDMI_INFOFRAME_TYPE_SPD:
680d6e94fe5Sriastradh 		return hdmi_spd_infoframe_pack(&frame->spd, buf, size);
681d6e94fe5Sriastradh 	case HDMI_INFOFRAME_TYPE_AUDIO:
682d6e94fe5Sriastradh 		return hdmi_audio_infoframe_pack(&frame->audio, buf, size);
683d6e94fe5Sriastradh 	case HDMI_INFOFRAME_TYPE_DRM:
684d6e94fe5Sriastradh 		return hdmi_drm_infoframe_pack(&frame->drm, buf, size);
685f3393e87Sriastradh 	default:
686f3393e87Sriastradh 		return -EINVAL;
687f3393e87Sriastradh 	}
688f3393e87Sriastradh }
689f3393e87Sriastradh 
690f3393e87Sriastradh int
hdmi_infoframe_unpack(union hdmi_infoframe * frame,const void * buf,size_t size)691f3393e87Sriastradh hdmi_infoframe_unpack(union hdmi_infoframe *frame, const void *buf,
692f3393e87Sriastradh     size_t size)
693f3393e87Sriastradh {
694f3393e87Sriastradh 	int ret;
695f3393e87Sriastradh 
6969f52d00eSriastradh 	memset(frame, 0, sizeof(*frame));
6979f52d00eSriastradh 
69891cb1d74Sriastradh 	ret = hdmi_infoframe_header_unpack(&frame->any, buf, size);
699f3393e87Sriastradh 	if (ret)
700f3393e87Sriastradh 		return ret;
70191cb1d74Sriastradh 	switch (frame->any.type) {
702f3393e87Sriastradh 	case HDMI_INFOFRAME_TYPE_VENDOR:
703f3393e87Sriastradh 		return hdmi_vendor_infoframe_unpack(&frame->vendor.hdmi, buf,
704f3393e87Sriastradh 		    size);
7055dd7fa73Sriastradh 	case HDMI_INFOFRAME_TYPE_AVI:
7065dd7fa73Sriastradh 		return hdmi_avi_infoframe_unpack(&frame->avi, buf, size);
7075dd7fa73Sriastradh 	case HDMI_INFOFRAME_TYPE_SPD:
7085dd7fa73Sriastradh 		return hdmi_spd_infoframe_unpack(&frame->spd, buf, size);
7095dd7fa73Sriastradh 	case HDMI_INFOFRAME_TYPE_AUDIO:
7105dd7fa73Sriastradh 		return hdmi_audio_infoframe_unpack(&frame->audio, buf, size);
7115dd7fa73Sriastradh 	case HDMI_INFOFRAME_TYPE_DRM:
7125dd7fa73Sriastradh 		return hdmi_drm_infoframe_unpack(&frame->drm, buf, size);
713f3393e87Sriastradh 	default:
714f3393e87Sriastradh 		return -EINVAL;
715f3393e87Sriastradh 	}
716f3393e87Sriastradh }
717f3393e87Sriastradh 
718f3393e87Sriastradh void
hdmi_infoframe_log(const char * level,struct device * device,const union hdmi_infoframe * frame)719f3393e87Sriastradh hdmi_infoframe_log(const char *level, struct device *device,
720f3393e87Sriastradh     const union hdmi_infoframe *frame)
721f3393e87Sriastradh {
722f3393e87Sriastradh 
723f3393e87Sriastradh 	hexdump(printf, device_xname(device), frame, sizeof(*frame));
724f3393e87Sriastradh }
725