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