Line data Source code
1 : /* $OpenBSD: linux_hdmi.c,v 1.1 2015/09/23 23:12:11 kettenis Exp $ */
2 : /*
3 : * Copyright (C) 2012 Avionic Design GmbH
4 : *
5 : * Permission is hereby granted, free of charge, to any person obtaining a
6 : * copy of this software and associated documentation files (the "Software"),
7 : * to deal in the Software without restriction, including without limitation
8 : * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 : * and/or sell copies of the Software, and to permit persons to whom the
10 : * Software is furnished to do so, subject to the following conditions:
11 : *
12 : * The above copyright notice and this permission notice (including the
13 : * next paragraph) shall be included in all copies or substantial portions
14 : * of the Software.
15 : *
16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 : * DEALINGS IN THE SOFTWARE.
23 : */
24 :
25 : #include "drmP.h"
26 : #include "linux_hdmi.h"
27 :
28 0 : static void hdmi_infoframe_checksum(void *buffer, size_t size)
29 : {
30 : u8 *ptr = buffer;
31 : u8 csum = 0;
32 : size_t i;
33 :
34 : /* compute checksum */
35 0 : for (i = 0; i < size; i++)
36 0 : csum += ptr[i];
37 :
38 0 : ptr[3] = 256 - csum;
39 0 : }
40 :
41 : /**
42 : * hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe
43 : * @frame: HDMI AVI infoframe
44 : *
45 : * Returns 0 on success or a negative error code on failure.
46 : */
47 0 : int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
48 : {
49 0 : memset(frame, 0, sizeof(*frame));
50 :
51 0 : frame->type = HDMI_INFOFRAME_TYPE_AVI;
52 0 : frame->version = 2;
53 0 : frame->length = HDMI_AVI_INFOFRAME_SIZE;
54 :
55 0 : return 0;
56 : }
57 : EXPORT_SYMBOL(hdmi_avi_infoframe_init);
58 :
59 : /**
60 : * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
61 : * @frame: HDMI AVI infoframe
62 : * @buffer: destination buffer
63 : * @size: size of buffer
64 : *
65 : * Packs the information contained in the @frame structure into a binary
66 : * representation that can be written into the corresponding controller
67 : * registers. Also computes the checksum as required by section 5.3.5 of
68 : * the HDMI 1.4 specification.
69 : *
70 : * Returns the number of bytes packed into the binary buffer or a negative
71 : * error code on failure.
72 : */
73 0 : ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
74 : size_t size)
75 : {
76 : u8 *ptr = buffer;
77 : size_t length;
78 :
79 0 : length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
80 :
81 0 : if (size < length)
82 0 : return -ENOSPC;
83 :
84 0 : memset(buffer, 0, size);
85 :
86 0 : ptr[0] = frame->type;
87 0 : ptr[1] = frame->version;
88 0 : ptr[2] = frame->length;
89 0 : ptr[3] = 0; /* checksum */
90 :
91 : /* start infoframe payload */
92 0 : ptr += HDMI_INFOFRAME_HEADER_SIZE;
93 :
94 0 : ptr[0] = ((frame->colorspace & 0x3) << 5) | (frame->scan_mode & 0x3);
95 :
96 : /*
97 : * Data byte 1, bit 4 has to be set if we provide the active format
98 : * aspect ratio
99 : */
100 0 : if (frame->active_aspect & 0xf)
101 0 : ptr[0] |= BIT(4);
102 :
103 : /* Bit 3 and 2 indicate if we transmit horizontal/vertical bar data */
104 0 : if (frame->top_bar || frame->bottom_bar)
105 0 : ptr[0] |= BIT(3);
106 :
107 0 : if (frame->left_bar || frame->right_bar)
108 0 : ptr[0] |= BIT(2);
109 :
110 0 : ptr[1] = ((frame->colorimetry & 0x3) << 6) |
111 0 : ((frame->picture_aspect & 0x3) << 4) |
112 0 : (frame->active_aspect & 0xf);
113 :
114 0 : ptr[2] = ((frame->extended_colorimetry & 0x7) << 4) |
115 0 : ((frame->quantization_range & 0x3) << 2) |
116 0 : (frame->nups & 0x3);
117 :
118 0 : if (frame->itc)
119 0 : ptr[2] |= BIT(7);
120 :
121 0 : ptr[3] = frame->video_code & 0x7f;
122 :
123 0 : ptr[4] = ((frame->ycc_quantization_range & 0x3) << 6) |
124 0 : ((frame->content_type & 0x3) << 4) |
125 0 : (frame->pixel_repeat & 0xf);
126 :
127 0 : ptr[5] = frame->top_bar & 0xff;
128 0 : ptr[6] = (frame->top_bar >> 8) & 0xff;
129 0 : ptr[7] = frame->bottom_bar & 0xff;
130 0 : ptr[8] = (frame->bottom_bar >> 8) & 0xff;
131 0 : ptr[9] = frame->left_bar & 0xff;
132 0 : ptr[10] = (frame->left_bar >> 8) & 0xff;
133 0 : ptr[11] = frame->right_bar & 0xff;
134 0 : ptr[12] = (frame->right_bar >> 8) & 0xff;
135 :
136 0 : hdmi_infoframe_checksum(buffer, length);
137 :
138 0 : return length;
139 0 : }
140 : EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
141 :
142 : /**
143 : * hdmi_spd_infoframe_init() - initialize an HDMI SPD infoframe
144 : * @frame: HDMI SPD infoframe
145 : * @vendor: vendor string
146 : * @product: product string
147 : *
148 : * Returns 0 on success or a negative error code on failure.
149 : */
150 0 : int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
151 : const char *vendor, const char *product)
152 : {
153 0 : memset(frame, 0, sizeof(*frame));
154 :
155 0 : frame->type = HDMI_INFOFRAME_TYPE_SPD;
156 0 : frame->version = 1;
157 0 : frame->length = HDMI_SPD_INFOFRAME_SIZE;
158 :
159 0 : strncpy(frame->vendor, vendor, sizeof(frame->vendor));
160 0 : strncpy(frame->product, product, sizeof(frame->product));
161 :
162 0 : return 0;
163 : }
164 : EXPORT_SYMBOL(hdmi_spd_infoframe_init);
165 :
166 : /**
167 : * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
168 : * @frame: HDMI SPD infoframe
169 : * @buffer: destination buffer
170 : * @size: size of buffer
171 : *
172 : * Packs the information contained in the @frame structure into a binary
173 : * representation that can be written into the corresponding controller
174 : * registers. Also computes the checksum as required by section 5.3.5 of
175 : * the HDMI 1.4 specification.
176 : *
177 : * Returns the number of bytes packed into the binary buffer or a negative
178 : * error code on failure.
179 : */
180 0 : ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
181 : size_t size)
182 : {
183 : u8 *ptr = buffer;
184 : size_t length;
185 :
186 0 : length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
187 :
188 0 : if (size < length)
189 0 : return -ENOSPC;
190 :
191 0 : memset(buffer, 0, size);
192 :
193 0 : ptr[0] = frame->type;
194 0 : ptr[1] = frame->version;
195 0 : ptr[2] = frame->length;
196 0 : ptr[3] = 0; /* checksum */
197 :
198 : /* start infoframe payload */
199 0 : ptr += HDMI_INFOFRAME_HEADER_SIZE;
200 :
201 0 : memcpy(ptr, frame->vendor, sizeof(frame->vendor));
202 0 : memcpy(ptr + 8, frame->product, sizeof(frame->product));
203 :
204 0 : ptr[24] = frame->sdi;
205 :
206 0 : hdmi_infoframe_checksum(buffer, length);
207 :
208 0 : return length;
209 0 : }
210 : EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
211 :
212 : /**
213 : * hdmi_audio_infoframe_init() - initialize an HDMI audio infoframe
214 : * @frame: HDMI audio infoframe
215 : *
216 : * Returns 0 on success or a negative error code on failure.
217 : */
218 0 : int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
219 : {
220 0 : memset(frame, 0, sizeof(*frame));
221 :
222 0 : frame->type = HDMI_INFOFRAME_TYPE_AUDIO;
223 0 : frame->version = 1;
224 0 : frame->length = HDMI_AUDIO_INFOFRAME_SIZE;
225 :
226 0 : return 0;
227 : }
228 : EXPORT_SYMBOL(hdmi_audio_infoframe_init);
229 :
230 : /**
231 : * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
232 : * @frame: HDMI audio infoframe
233 : * @buffer: destination buffer
234 : * @size: size of buffer
235 : *
236 : * Packs the information contained in the @frame structure into a binary
237 : * representation that can be written into the corresponding controller
238 : * registers. Also computes the checksum as required by section 5.3.5 of
239 : * the HDMI 1.4 specification.
240 : *
241 : * Returns the number of bytes packed into the binary buffer or a negative
242 : * error code on failure.
243 : */
244 0 : ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
245 : void *buffer, size_t size)
246 : {
247 : unsigned char channels;
248 : u8 *ptr = buffer;
249 : size_t length;
250 :
251 0 : length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
252 :
253 0 : if (size < length)
254 0 : return -ENOSPC;
255 :
256 0 : memset(buffer, 0, size);
257 :
258 0 : if (frame->channels >= 2)
259 0 : channels = frame->channels - 1;
260 : else
261 : channels = 0;
262 :
263 0 : ptr[0] = frame->type;
264 0 : ptr[1] = frame->version;
265 0 : ptr[2] = frame->length;
266 0 : ptr[3] = 0; /* checksum */
267 :
268 : /* start infoframe payload */
269 0 : ptr += HDMI_INFOFRAME_HEADER_SIZE;
270 :
271 0 : ptr[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7);
272 0 : ptr[1] = ((frame->sample_frequency & 0x7) << 2) |
273 0 : (frame->sample_size & 0x3);
274 0 : ptr[2] = frame->coding_type_ext & 0x1f;
275 0 : ptr[3] = frame->channel_allocation;
276 0 : ptr[4] = (frame->level_shift_value & 0xf) << 3;
277 :
278 0 : if (frame->downmix_inhibit)
279 0 : ptr[4] |= BIT(7);
280 :
281 0 : hdmi_infoframe_checksum(buffer, length);
282 :
283 0 : return length;
284 0 : }
285 : EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
286 :
287 : /**
288 : * hdmi_vendor_infoframe_init() - initialize an HDMI vendor infoframe
289 : * @frame: HDMI vendor infoframe
290 : *
291 : * Returns 0 on success or a negative error code on failure.
292 : */
293 0 : int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
294 : {
295 0 : memset(frame, 0, sizeof(*frame));
296 :
297 0 : frame->type = HDMI_INFOFRAME_TYPE_VENDOR;
298 0 : frame->version = 1;
299 :
300 0 : frame->oui = HDMI_IEEE_OUI;
301 :
302 : /*
303 : * 0 is a valid value for s3d_struct, so we use a special "not set"
304 : * value
305 : */
306 0 : frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
307 :
308 0 : return 0;
309 : }
310 : EXPORT_SYMBOL(hdmi_vendor_infoframe_init);
311 :
312 : /**
313 : * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
314 : * @frame: HDMI infoframe
315 : * @buffer: destination buffer
316 : * @size: size of buffer
317 : *
318 : * Packs the information contained in the @frame structure into a binary
319 : * representation that can be written into the corresponding controller
320 : * registers. Also computes the checksum as required by section 5.3.5 of
321 : * the HDMI 1.4 specification.
322 : *
323 : * Returns the number of bytes packed into the binary buffer or a negative
324 : * error code on failure.
325 : */
326 0 : ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
327 : void *buffer, size_t size)
328 : {
329 : u8 *ptr = buffer;
330 : size_t length;
331 :
332 : /* empty info frame */
333 0 : if (frame->vic == 0 && frame->s3d_struct == HDMI_3D_STRUCTURE_INVALID)
334 0 : return -EINVAL;
335 :
336 : /* only one of those can be supplied */
337 0 : if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
338 0 : return -EINVAL;
339 :
340 : /* for side by side (half) we also need to provide 3D_Ext_Data */
341 0 : if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
342 0 : frame->length = 6;
343 : else
344 0 : frame->length = 5;
345 :
346 0 : length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
347 :
348 0 : if (size < length)
349 0 : return -ENOSPC;
350 :
351 0 : memset(buffer, 0, size);
352 :
353 0 : ptr[0] = frame->type;
354 0 : ptr[1] = frame->version;
355 0 : ptr[2] = frame->length;
356 0 : ptr[3] = 0; /* checksum */
357 :
358 : /* HDMI OUI */
359 0 : ptr[4] = 0x03;
360 0 : ptr[5] = 0x0c;
361 0 : ptr[6] = 0x00;
362 :
363 0 : if (frame->vic) {
364 0 : ptr[7] = 0x1 << 5; /* video format */
365 0 : ptr[8] = frame->vic;
366 0 : } else {
367 0 : ptr[7] = 0x2 << 5; /* video format */
368 0 : ptr[8] = (frame->s3d_struct & 0xf) << 4;
369 0 : if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
370 0 : ptr[9] = (frame->s3d_ext_data & 0xf) << 4;
371 : }
372 :
373 0 : hdmi_infoframe_checksum(buffer, length);
374 :
375 0 : return length;
376 0 : }
377 : EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
378 :
379 : /*
380 : * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
381 : */
382 : static ssize_t
383 0 : hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
384 : void *buffer, size_t size)
385 : {
386 : /* we only know about HDMI vendor infoframes */
387 0 : if (frame->any.oui != HDMI_IEEE_OUI)
388 0 : return -EINVAL;
389 :
390 0 : return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
391 0 : }
392 :
393 : /**
394 : * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
395 : * @frame: HDMI infoframe
396 : * @buffer: destination buffer
397 : * @size: size of buffer
398 : *
399 : * Packs the information contained in the @frame structure into a binary
400 : * representation that can be written into the corresponding controller
401 : * registers. Also computes the checksum as required by section 5.3.5 of
402 : * the HDMI 1.4 specification.
403 : *
404 : * Returns the number of bytes packed into the binary buffer or a negative
405 : * error code on failure.
406 : */
407 : ssize_t
408 0 : hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
409 : {
410 : ssize_t length;
411 :
412 0 : switch (frame->any.type) {
413 : case HDMI_INFOFRAME_TYPE_AVI:
414 0 : length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size);
415 0 : break;
416 : case HDMI_INFOFRAME_TYPE_SPD:
417 0 : length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size);
418 0 : break;
419 : case HDMI_INFOFRAME_TYPE_AUDIO:
420 0 : length = hdmi_audio_infoframe_pack(&frame->audio, buffer, size);
421 0 : break;
422 : case HDMI_INFOFRAME_TYPE_VENDOR:
423 0 : length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
424 : buffer, size);
425 0 : break;
426 : default:
427 0 : WARN(1, "Bad infoframe type %d\n", frame->any.type);
428 : length = -EINVAL;
429 0 : }
430 :
431 0 : return length;
432 : }
433 : EXPORT_SYMBOL(hdmi_infoframe_pack);
|