1 // SPDX-License-Identifier: GPL-2.0-only OR MIT
2 /* Copyright 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> */
3
4 #include <linux/kernel.h>
5 #include <linux/err.h>
6 #include <linux/math.h>
7 #include <linux/string.h>
8 #include <linux/slab.h>
9
10 #include <sound/pcm.h> // for sound format masks
11
12 #include "parser.h"
13 #include "trace.h"
14
15 #define DCP_PARSE_HEADER 0xd3
16
17 enum dcp_parse_type {
18 DCP_TYPE_DICTIONARY = 1,
19 DCP_TYPE_ARRAY = 2,
20 DCP_TYPE_INT64 = 4,
21 DCP_TYPE_STRING = 9,
22 DCP_TYPE_BLOB = 10,
23 DCP_TYPE_BOOL = 11
24 };
25
26 struct dcp_parse_tag {
27 unsigned int size : 24;
28 enum dcp_parse_type type : 5;
29 unsigned int padding : 2;
30 bool last : 1;
31 } __packed;
32
parse_bytes(struct dcp_parse_ctx * ctx,size_t count)33 static const void *parse_bytes(struct dcp_parse_ctx *ctx, size_t count)
34 {
35 const void *ptr = ctx->blob + ctx->pos;
36
37 if (ctx->pos + count > ctx->len)
38 return ERR_PTR(-EINVAL);
39
40 ctx->pos += count;
41 return ptr;
42 }
43
parse_u32(struct dcp_parse_ctx * ctx)44 static const u32 *parse_u32(struct dcp_parse_ctx *ctx)
45 {
46 return parse_bytes(ctx, sizeof(u32));
47 }
48
parse_tag(struct dcp_parse_ctx * ctx)49 static const struct dcp_parse_tag *parse_tag(struct dcp_parse_ctx *ctx)
50 {
51 const struct dcp_parse_tag *tag;
52
53 /* Align to 32-bits */
54 ctx->pos = round_up(ctx->pos, 4);
55
56 tag = parse_bytes(ctx, sizeof(struct dcp_parse_tag));
57
58 if (IS_ERR(tag))
59 return tag;
60
61 if (tag->padding)
62 return ERR_PTR(-EINVAL);
63
64 return tag;
65 }
66
parse_tag_of_type(struct dcp_parse_ctx * ctx,enum dcp_parse_type type)67 static const struct dcp_parse_tag *parse_tag_of_type(struct dcp_parse_ctx *ctx,
68 enum dcp_parse_type type)
69 {
70 const struct dcp_parse_tag *tag = parse_tag(ctx);
71
72 if (IS_ERR(tag))
73 return tag;
74
75 if (tag->type != type)
76 return ERR_PTR(-EINVAL);
77
78 return tag;
79 }
80
skip(struct dcp_parse_ctx * handle)81 static int skip(struct dcp_parse_ctx *handle)
82 {
83 const struct dcp_parse_tag *tag = parse_tag(handle);
84 int ret = 0;
85 int i;
86
87 if (IS_ERR(tag))
88 return PTR_ERR(tag);
89
90 switch (tag->type) {
91 case DCP_TYPE_DICTIONARY:
92 for (i = 0; i < tag->size; ++i) {
93 ret |= skip(handle); /* key */
94 ret |= skip(handle); /* value */
95 }
96
97 return ret;
98
99 case DCP_TYPE_ARRAY:
100 for (i = 0; i < tag->size; ++i)
101 ret |= skip(handle);
102
103 return ret;
104
105 case DCP_TYPE_INT64:
106 handle->pos += sizeof(s64);
107 return 0;
108
109 case DCP_TYPE_STRING:
110 case DCP_TYPE_BLOB:
111 handle->pos += tag->size;
112 return 0;
113
114 case DCP_TYPE_BOOL:
115 return 0;
116
117 default:
118 return -EINVAL;
119 }
120 }
121
skip_pair(struct dcp_parse_ctx * handle)122 static int skip_pair(struct dcp_parse_ctx *handle)
123 {
124 int ret;
125
126 ret = skip(handle);
127 if (ret)
128 return ret;
129
130 return skip(handle);
131 }
132
consume_string(struct dcp_parse_ctx * ctx,const char * specimen)133 static bool consume_string(struct dcp_parse_ctx *ctx, const char *specimen)
134 {
135 const struct dcp_parse_tag *tag;
136 const char *key;
137 ctx->pos = round_up(ctx->pos, 4);
138
139 if (ctx->pos + sizeof(*tag) + strlen(specimen) - 1 > ctx->len)
140 return false;
141 tag = ctx->blob + ctx->pos;
142 key = ctx->blob + ctx->pos + sizeof(*tag);
143 if (tag->padding)
144 return false;
145
146 if (tag->type != DCP_TYPE_STRING ||
147 tag->size != strlen(specimen) ||
148 strncmp(key, specimen, tag->size))
149 return false;
150
151 skip(ctx);
152 return true;
153 }
154
155 /* Caller must free the result */
parse_string(struct dcp_parse_ctx * handle)156 static char *parse_string(struct dcp_parse_ctx *handle)
157 {
158 const struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_STRING);
159 const char *in;
160 char *out;
161
162 if (IS_ERR(tag))
163 return (void *)tag;
164
165 in = parse_bytes(handle, tag->size);
166 if (IS_ERR(in))
167 return (void *)in;
168
169 out = kmalloc(tag->size + 1, GFP_KERNEL);
170
171 memcpy(out, in, tag->size);
172 out[tag->size] = '\0';
173 return out;
174 }
175
parse_int(struct dcp_parse_ctx * handle,s64 * value)176 static int parse_int(struct dcp_parse_ctx *handle, s64 *value)
177 {
178 const void *tag = parse_tag_of_type(handle, DCP_TYPE_INT64);
179 const s64 *in;
180
181 if (IS_ERR(tag))
182 return PTR_ERR(tag);
183
184 in = parse_bytes(handle, sizeof(s64));
185
186 if (IS_ERR(in))
187 return PTR_ERR(in);
188
189 memcpy(value, in, sizeof(*value));
190 return 0;
191 }
192
parse_bool(struct dcp_parse_ctx * handle,bool * b)193 static int parse_bool(struct dcp_parse_ctx *handle, bool *b)
194 {
195 const struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BOOL);
196
197 if (IS_ERR(tag))
198 return PTR_ERR(tag);
199
200 *b = !!tag->size;
201 return 0;
202 }
203
parse_blob(struct dcp_parse_ctx * handle,size_t size,u8 const ** blob)204 static int parse_blob(struct dcp_parse_ctx *handle, size_t size, u8 const **blob)
205 {
206 const struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BLOB);
207 const u8 *out;
208
209 if (IS_ERR(tag))
210 return PTR_ERR(tag);
211
212 if (tag->size < size)
213 return -EINVAL;
214
215 out = parse_bytes(handle, tag->size);
216
217 if (IS_ERR(out))
218 return PTR_ERR(out);
219
220 *blob = out;
221 return 0;
222 }
223
224 struct iterator {
225 struct dcp_parse_ctx *handle;
226 u32 idx, len;
227 };
228
iterator_begin(struct dcp_parse_ctx * handle,struct iterator * it,bool dict)229 static int iterator_begin(struct dcp_parse_ctx *handle, struct iterator *it,
230 bool dict)
231 {
232 const struct dcp_parse_tag *tag;
233 enum dcp_parse_type type = dict ? DCP_TYPE_DICTIONARY : DCP_TYPE_ARRAY;
234
235 *it = (struct iterator) {
236 .handle = handle,
237 .idx = 0
238 };
239
240 tag = parse_tag_of_type(it->handle, type);
241 if (IS_ERR(tag))
242 return PTR_ERR(tag);
243
244 it->len = tag->size;
245 return 0;
246 }
247
248 #define dcp_parse_foreach_in_array(handle, it) \
249 for (iterator_begin(handle, &it, false); it.idx < it.len; ++it.idx)
250 #define dcp_parse_foreach_in_dict(handle, it) \
251 for (iterator_begin(handle, &it, true); it.idx < it.len; ++it.idx)
252
parse(const void * blob,size_t size,struct dcp_parse_ctx * ctx)253 int parse(const void *blob, size_t size, struct dcp_parse_ctx *ctx)
254 {
255 const u32 *header;
256
257 *ctx = (struct dcp_parse_ctx) {
258 .blob = blob,
259 .len = size,
260 .pos = 0,
261 };
262
263 header = parse_u32(ctx);
264 if (IS_ERR(header))
265 return PTR_ERR(header);
266
267 if (*header != DCP_PARSE_HEADER)
268 return -EINVAL;
269
270 return 0;
271 }
272
parse_dimension(struct dcp_parse_ctx * handle,struct dimension * dim)273 static int parse_dimension(struct dcp_parse_ctx *handle, struct dimension *dim)
274 {
275 struct iterator it;
276 int ret = 0;
277
278 dcp_parse_foreach_in_dict(handle, it) {
279 char *key = parse_string(it.handle);
280
281 if (IS_ERR(key))
282 ret = PTR_ERR(key);
283 else if (!strcmp(key, "Active"))
284 ret = parse_int(it.handle, &dim->active);
285 else if (!strcmp(key, "Total"))
286 ret = parse_int(it.handle, &dim->total);
287 else if (!strcmp(key, "FrontPorch"))
288 ret = parse_int(it.handle, &dim->front_porch);
289 else if (!strcmp(key, "SyncWidth"))
290 ret = parse_int(it.handle, &dim->sync_width);
291 else if (!strcmp(key, "PreciseSyncRate"))
292 ret = parse_int(it.handle, &dim->precise_sync_rate);
293 else
294 skip(it.handle);
295
296 if (!IS_ERR_OR_NULL(key))
297 kfree(key);
298
299 if (ret)
300 return ret;
301 }
302
303 return 0;
304 }
305
306 struct color_mode {
307 s64 colorimetry;
308 s64 depth;
309 s64 dynamic_range;
310 s64 eotf;
311 s64 id;
312 s64 pixel_encoding;
313 s64 score;
314 };
315
fill_color_mode(struct dcp_color_mode * color,struct color_mode * cmode)316 static int fill_color_mode(struct dcp_color_mode *color,
317 struct color_mode *cmode)
318 {
319 if (color->score >= cmode->score)
320 return 0;
321
322 if (cmode->colorimetry < 0 || cmode->colorimetry >= DCP_COLORIMETRY_COUNT)
323 return -EINVAL;
324 if (cmode->depth < 8 || cmode->depth > 12)
325 return -EINVAL;
326 if (cmode->dynamic_range < 0 || cmode->dynamic_range >= DCP_COLOR_YCBCR_RANGE_COUNT)
327 return -EINVAL;
328 if (cmode->eotf < 0 || cmode->eotf >= DCP_EOTF_COUNT)
329 return -EINVAL;
330 if (cmode->pixel_encoding < 0 || cmode->pixel_encoding >= DCP_COLOR_FORMAT_COUNT)
331 return -EINVAL;
332
333 color->score = cmode->score;
334 color->id = cmode->id;
335 color->eotf = cmode->eotf;
336 color->format = cmode->pixel_encoding;
337 color->colorimetry = cmode->colorimetry;
338 color->range = cmode->dynamic_range;
339 color->depth = cmode->depth;
340
341 return 0;
342 }
343
parse_color_modes(struct dcp_parse_ctx * handle,struct dcp_display_mode * out)344 static int parse_color_modes(struct dcp_parse_ctx *handle,
345 struct dcp_display_mode *out)
346 {
347 struct iterator outer_it;
348 int ret = 0;
349 out->sdr_444.score = -1;
350 out->sdr_rgb.score = -1;
351 out->best.score = -1;
352
353 dcp_parse_foreach_in_array(handle, outer_it) {
354 struct iterator it;
355 bool is_virtual = true;
356 struct color_mode cmode;
357
358 dcp_parse_foreach_in_dict(handle, it) {
359 char *key = parse_string(it.handle);
360
361 if (IS_ERR(key))
362 ret = PTR_ERR(key);
363 else if (!strcmp(key, "Colorimetry"))
364 ret = parse_int(it.handle, &cmode.colorimetry);
365 else if (!strcmp(key, "Depth"))
366 ret = parse_int(it.handle, &cmode.depth);
367 else if (!strcmp(key, "DynamicRange"))
368 ret = parse_int(it.handle, &cmode.dynamic_range);
369 else if (!strcmp(key, "EOTF"))
370 ret = parse_int(it.handle, &cmode.eotf);
371 else if (!strcmp(key, "ID"))
372 ret = parse_int(it.handle, &cmode.id);
373 else if (!strcmp(key, "IsVirtual"))
374 ret = parse_bool(it.handle, &is_virtual);
375 else if (!strcmp(key, "PixelEncoding"))
376 ret = parse_int(it.handle, &cmode.pixel_encoding);
377 else if (!strcmp(key, "Score"))
378 ret = parse_int(it.handle, &cmode.score);
379 else
380 skip(it.handle);
381
382 if (!IS_ERR_OR_NULL(key))
383 kfree(key);
384
385 if (ret)
386 return ret;
387 }
388
389 /* Skip virtual or partial entries */
390 if (is_virtual || cmode.score < 0 || cmode.id < 0)
391 continue;
392
393 trace_iomfb_color_mode(handle->dcp, cmode.id, cmode.score,
394 cmode.depth, cmode.colorimetry,
395 cmode.eotf, cmode.dynamic_range,
396 cmode.pixel_encoding);
397
398 if (cmode.eotf == DCP_EOTF_SDR_GAMMA) {
399 if (cmode.pixel_encoding == DCP_COLOR_FORMAT_RGB &&
400 cmode.depth <= 10)
401 fill_color_mode(&out->sdr_rgb, &cmode);
402 else if (cmode.pixel_encoding == DCP_COLOR_FORMAT_YCBCR444 &&
403 cmode.depth <= 10)
404 fill_color_mode(&out->sdr_444, &cmode);
405 fill_color_mode(&out->sdr, &cmode);
406 }
407 fill_color_mode(&out->best, &cmode);
408 }
409
410 return 0;
411 }
412
413 /*
414 * Calculate the pixel clock for a mode given the 16:16 fixed-point refresh
415 * rate. The pixel clock is the refresh rate times the pixel count. DRM
416 * specifies the clock in kHz. The intermediate result may overflow a u32, so
417 * use a u64 where required.
418 */
calculate_clock(struct dimension * horiz,struct dimension * vert)419 static u32 calculate_clock(struct dimension *horiz, struct dimension *vert)
420 {
421 u32 pixels = horiz->total * vert->total;
422 u64 clock = mul_u32_u32(pixels, vert->precise_sync_rate);
423
424 return DIV_ROUND_CLOSEST_ULL(clock >> 16, 1000);
425 }
426
parse_mode(struct dcp_parse_ctx * handle,struct dcp_display_mode * out,s64 * score,int width_mm,int height_mm,unsigned notch_height)427 static int parse_mode(struct dcp_parse_ctx *handle,
428 struct dcp_display_mode *out, s64 *score, int width_mm,
429 int height_mm, unsigned notch_height)
430 {
431 int ret = 0;
432 struct iterator it;
433 struct dimension horiz, vert;
434 s64 id = -1;
435 s64 best_color_mode = -1;
436 bool is_virtual = false;
437 struct drm_display_mode *mode = &out->mode;
438
439 dcp_parse_foreach_in_dict(handle, it) {
440 char *key = parse_string(it.handle);
441
442 if (IS_ERR(key))
443 ret = PTR_ERR(key);
444 else if (is_virtual)
445 skip(it.handle);
446 else if (!strcmp(key, "HorizontalAttributes"))
447 ret = parse_dimension(it.handle, &horiz);
448 else if (!strcmp(key, "VerticalAttributes"))
449 ret = parse_dimension(it.handle, &vert);
450 else if (!strcmp(key, "ColorModes"))
451 ret = parse_color_modes(it.handle, out);
452 else if (!strcmp(key, "ID"))
453 ret = parse_int(it.handle, &id);
454 else if (!strcmp(key, "IsVirtual"))
455 ret = parse_bool(it.handle, &is_virtual);
456 else if (!strcmp(key, "Score"))
457 ret = parse_int(it.handle, score);
458 else
459 skip(it.handle);
460
461 if (!IS_ERR_OR_NULL(key))
462 kfree(key);
463
464 if (ret) {
465 trace_iomfb_parse_mode_fail(id, &horiz, &vert, best_color_mode, is_virtual, *score);
466 return ret;
467 }
468 }
469 if (out->sdr_rgb.score >= 0)
470 best_color_mode = out->sdr_rgb.id;
471 else if (out->sdr_444.score >= 0)
472 best_color_mode = out->sdr_444.id;
473 else if (out->sdr.score >= 0)
474 best_color_mode = out->sdr.id;
475 else if (out->best.score >= 0)
476 best_color_mode = out->best.id;
477
478 trace_iomfb_parse_mode_success(id, &horiz, &vert, best_color_mode,
479 is_virtual, *score);
480
481 /*
482 * Reject modes without valid color mode.
483 */
484 if (best_color_mode < 0)
485 return -EINVAL;
486
487 /*
488 * We need to skip virtual modes. In some cases, virtual modes are "too
489 * big" for the monitor and can cause breakage. It is unclear why the
490 * DCP reports these modes at all. Treat as a recoverable error.
491 */
492 if (is_virtual)
493 return -EINVAL;
494
495 /*
496 * HACK:
497 * Ignore the 120 Hz mode on j314/j316 (identified by resolution).
498 * DCP limits normal swaps to 60 Hz anyway and the 120 Hz mode might
499 * cause choppiness with X11.
500 * Just downscoring it and thus making the 60 Hz mode the preferred mode
501 * seems not enough for some user space.
502 */
503 if (vert.precise_sync_rate >> 16 == 120 &&
504 ((horiz.active == 3024 && vert.active == 1964) ||
505 (horiz.active == 3456 && vert.active == 2234)))
506 return -EINVAL;
507
508 /*
509 * HACK: reject refresh modes with a pixel clock above 926484,480 kHz
510 * (bandwidth limit reported by dcp). This allows 4k 100Hz and
511 * 5k 60Hz but not much beyond.
512 * DSC setup seems to require additional steps
513 */
514 if (calculate_clock(&horiz, &vert) > 926484) {
515 pr_info("dcp: rejecting mode %lldx%lld@%lld.%03lld (pixel clk:%d)\n",
516 horiz.active, vert.active, vert.precise_sync_rate >> 16,
517 ((1000 * vert.precise_sync_rate) >> 16) % 1000,
518 calculate_clock(&horiz, &vert));
519 return -EINVAL;
520 }
521
522 vert.active -= notch_height;
523 vert.sync_width += notch_height;
524
525 /* From here we must succeed. Start filling out the mode. */
526 *mode = (struct drm_display_mode) {
527 .type = DRM_MODE_TYPE_DRIVER,
528 .clock = calculate_clock(&horiz, &vert),
529
530 .vdisplay = vert.active,
531 .vsync_start = vert.active + vert.front_porch,
532 .vsync_end = vert.active + vert.front_porch + vert.sync_width,
533 .vtotal = vert.total,
534
535 .hdisplay = horiz.active,
536 .hsync_start = horiz.active + horiz.front_porch,
537 .hsync_end = horiz.active + horiz.front_porch +
538 horiz.sync_width,
539 .htotal = horiz.total,
540
541 .width_mm = width_mm,
542 .height_mm = height_mm,
543 };
544
545 drm_mode_set_name(mode);
546
547 out->timing_mode_id = id;
548 out->color_mode_id = best_color_mode;
549
550 trace_iomfb_timing_mode(handle->dcp, id, *score, horiz.active,
551 vert.active, vert.precise_sync_rate,
552 best_color_mode);
553
554 return 0;
555 }
556
enumerate_modes(struct dcp_parse_ctx * handle,unsigned int * count,int width_mm,int height_mm,unsigned notch_height)557 struct dcp_display_mode *enumerate_modes(struct dcp_parse_ctx *handle,
558 unsigned int *count, int width_mm,
559 int height_mm, unsigned notch_height)
560 {
561 struct iterator it;
562 int ret;
563 struct dcp_display_mode *mode, *modes;
564 struct dcp_display_mode *best_mode = NULL;
565 s64 score, best_score = -1;
566
567 ret = iterator_begin(handle, &it, false);
568
569 if (ret)
570 return ERR_PTR(ret);
571
572 /* Start with a worst case allocation */
573 modes = kmalloc_array(it.len, sizeof(*modes), GFP_KERNEL);
574 *count = 0;
575
576 if (!modes)
577 return ERR_PTR(-ENOMEM);
578
579 for (; it.idx < it.len; ++it.idx) {
580 mode = &modes[*count];
581 ret = parse_mode(it.handle, mode, &score, width_mm, height_mm, notch_height);
582
583 /* Errors for a single mode are recoverable -- just skip it. */
584 if (ret)
585 continue;
586
587 /* Process a successful mode */
588 (*count)++;
589
590 if (score > best_score) {
591 best_score = score;
592 best_mode = mode;
593 }
594 }
595
596 if (best_mode != NULL)
597 best_mode->mode.type |= DRM_MODE_TYPE_PREFERRED;
598
599 return modes;
600 }
601
parse_display_attributes(struct dcp_parse_ctx * handle,int * width_mm,int * height_mm)602 int parse_display_attributes(struct dcp_parse_ctx *handle, int *width_mm,
603 int *height_mm)
604 {
605 int ret = 0;
606 struct iterator it;
607 s64 width_cm = 0, height_cm = 0;
608
609 dcp_parse_foreach_in_dict(handle, it) {
610 char *key = parse_string(it.handle);
611
612 if (IS_ERR(key))
613 ret = PTR_ERR(key);
614 else if (!strcmp(key, "MaxHorizontalImageSize"))
615 ret = parse_int(it.handle, &width_cm);
616 else if (!strcmp(key, "MaxVerticalImageSize"))
617 ret = parse_int(it.handle, &height_cm);
618 else
619 skip(it.handle);
620
621 if (!IS_ERR_OR_NULL(key))
622 kfree(key);
623
624 if (ret)
625 return ret;
626 }
627
628 /* 1cm = 10mm */
629 *width_mm = 10 * width_cm;
630 *height_mm = 10 * height_cm;
631
632 return 0;
633 }
634
parse_epic_service_init(struct dcp_parse_ctx * handle,const char ** name,const char ** class,s64 * unit)635 int parse_epic_service_init(struct dcp_parse_ctx *handle, const char **name,
636 const char **class, s64 *unit)
637 {
638 int ret = 0;
639 struct iterator it;
640 bool parsed_unit = false;
641 bool parsed_name = false;
642 bool parsed_class = false;
643
644 *name = ERR_PTR(-ENOENT);
645 *class = ERR_PTR(-ENOENT);
646
647 dcp_parse_foreach_in_dict(handle, it) {
648 char *key = parse_string(it.handle);
649
650 if (IS_ERR(key)) {
651 ret = PTR_ERR(key);
652 break;
653 }
654
655 if (!strcmp(key, "EPICName")) {
656 *name = parse_string(it.handle);
657 if (IS_ERR(*name))
658 ret = PTR_ERR(*name);
659 else
660 parsed_name = true;
661 } else if (!strcmp(key, "EPICProviderClass")) {
662 *class = parse_string(it.handle);
663 if (IS_ERR(*class))
664 ret = PTR_ERR(*class);
665 else
666 parsed_class = true;
667 } else if (!strcmp(key, "EPICUnit")) {
668 ret = parse_int(it.handle, unit);
669 if (!ret)
670 parsed_unit = true;
671 } else {
672 skip(it.handle);
673 }
674
675 kfree(key);
676 if (ret)
677 break;
678 }
679
680 if (!parsed_unit || !parsed_name || !parsed_class)
681 ret = -ENOENT;
682
683 if (ret) {
684 if (!IS_ERR(*name)) {
685 kfree(*name);
686 *name = ERR_PTR(ret);
687 }
688 if (!IS_ERR(*class)) {
689 kfree(*class);
690 *class = ERR_PTR(ret);
691 }
692 }
693
694 return ret;
695 }
696
parse_sample_rate_bit(struct dcp_parse_ctx * handle,unsigned int * ratebit)697 static int parse_sample_rate_bit(struct dcp_parse_ctx *handle, unsigned int *ratebit)
698 {
699 s64 rate;
700 int ret = parse_int(handle, &rate);
701
702 if (ret)
703 return ret;
704
705 *ratebit = snd_pcm_rate_to_rate_bit(rate);
706 if (*ratebit == SNDRV_PCM_RATE_KNOT) {
707 /*
708 * The rate wasn't recognized, and unless we supply
709 * a supplementary constraint, the SNDRV_PCM_RATE_KNOT bit
710 * will allow any rate. So clear it.
711 */
712 *ratebit = 0;
713 }
714
715 return 0;
716 }
717
parse_sample_fmtbit(struct dcp_parse_ctx * handle,u64 * fmtbit)718 static int parse_sample_fmtbit(struct dcp_parse_ctx *handle, u64 *fmtbit)
719 {
720 s64 sample_size;
721 int ret = parse_int(handle, &sample_size);
722
723 if (ret)
724 return ret;
725
726 switch (sample_size) {
727 case 16:
728 *fmtbit = SNDRV_PCM_FMTBIT_S16;
729 break;
730 case 20:
731 *fmtbit = SNDRV_PCM_FMTBIT_S20;
732 break;
733 case 24:
734 *fmtbit = SNDRV_PCM_FMTBIT_S24;
735 break;
736 case 32:
737 *fmtbit = SNDRV_PCM_FMTBIT_S32;
738 break;
739 default:
740 *fmtbit = 0;
741 break;
742 }
743
744 return 0;
745 }
746
747 static struct {
748 const char *label;
749 u8 type;
750 } chan_position_names[] = {
751 { "Front Left", SNDRV_CHMAP_FL },
752 { "Front Right", SNDRV_CHMAP_FR },
753 { "Rear Left", SNDRV_CHMAP_RL },
754 { "Rear Right", SNDRV_CHMAP_RR },
755 { "Front Center", SNDRV_CHMAP_FC },
756 { "Low Frequency Effects", SNDRV_CHMAP_LFE },
757 { "Rear Center", SNDRV_CHMAP_RC },
758 { "Front Left Center", SNDRV_CHMAP_FLC },
759 { "Front Right Center", SNDRV_CHMAP_FRC },
760 { "Rear Left Center", SNDRV_CHMAP_RLC },
761 { "Rear Right Center", SNDRV_CHMAP_RRC },
762 { "Front Left Wide", SNDRV_CHMAP_FLW },
763 { "Front Right Wide", SNDRV_CHMAP_FRW },
764 { "Front Left High", SNDRV_CHMAP_FLH },
765 { "Front Center High", SNDRV_CHMAP_FCH },
766 { "Front Right High", SNDRV_CHMAP_FRH },
767 { "Top Center", SNDRV_CHMAP_TC },
768 };
769
append_chmap(struct snd_pcm_chmap_elem * chmap,u8 type)770 static void append_chmap(struct snd_pcm_chmap_elem *chmap, u8 type)
771 {
772 if (!chmap || chmap->channels >= ARRAY_SIZE(chmap->map))
773 return;
774
775 chmap->map[chmap->channels] = type;
776 chmap->channels++;
777 }
778
parse_chmap(struct dcp_parse_ctx * handle,struct snd_pcm_chmap_elem * chmap)779 static int parse_chmap(struct dcp_parse_ctx *handle, struct snd_pcm_chmap_elem *chmap)
780 {
781 struct iterator it;
782 int i, ret;
783
784 if (!chmap) {
785 skip(handle);
786 return 0;
787 }
788
789 chmap->channels = 0;
790
791 dcp_parse_foreach_in_array(handle, it) {
792 for (i = 0; i < ARRAY_SIZE(chan_position_names); i++)
793 if (consume_string(it.handle, chan_position_names[i].label))
794 break;
795
796 if (i == ARRAY_SIZE(chan_position_names)) {
797 ret = skip(it.handle);
798 if (ret)
799 return ret;
800
801 append_chmap(chmap, SNDRV_CHMAP_UNKNOWN);
802 continue;
803 }
804
805 append_chmap(chmap, chan_position_names[i].type);
806 }
807
808 return 0;
809 }
810
parse_chan_layout_element(struct dcp_parse_ctx * handle,unsigned int * nchans_out,struct snd_pcm_chmap_elem * chmap)811 static int parse_chan_layout_element(struct dcp_parse_ctx *handle,
812 unsigned int *nchans_out,
813 struct snd_pcm_chmap_elem *chmap)
814 {
815 struct iterator it;
816 int ret;
817 s64 nchans = 0;
818
819 dcp_parse_foreach_in_dict(handle, it) {
820 if (consume_string(it.handle, "ActiveChannelCount"))
821 ret = parse_int(it.handle, &nchans);
822 else if (consume_string(it.handle, "ChannelLayout"))
823 ret = parse_chmap(it.handle, chmap);
824 else
825 ret = skip_pair(it.handle);
826
827 if (ret)
828 return ret;
829 }
830
831 if (nchans_out)
832 *nchans_out = nchans;
833
834 return 0;
835 }
836
parse_nchans_mask(struct dcp_parse_ctx * handle,unsigned int * mask)837 static int parse_nchans_mask(struct dcp_parse_ctx *handle, unsigned int *mask)
838 {
839 struct iterator it;
840 int ret;
841
842 *mask = 0;
843
844 dcp_parse_foreach_in_array(handle, it) {
845 int nchans;
846
847 ret = parse_chan_layout_element(it.handle, &nchans, NULL);
848 if (ret)
849 return ret;
850 *mask |= 1 << nchans;
851 }
852
853 return 0;
854 }
855
parse_avep_element(struct dcp_parse_ctx * handle,struct dcp_sound_format_mask * sieve,struct dcp_sound_format_mask * hits)856 static int parse_avep_element(struct dcp_parse_ctx *handle,
857 struct dcp_sound_format_mask *sieve,
858 struct dcp_sound_format_mask *hits)
859 {
860 struct dcp_sound_format_mask mask = {0, 0, 0};
861 struct iterator it;
862 int ret;
863
864 dcp_parse_foreach_in_dict(handle, it) {
865 if (consume_string(handle, "StreamSampleRate"))
866 ret = parse_sample_rate_bit(it.handle, &mask.rates);
867 else if (consume_string(handle, "SampleSize"))
868 ret = parse_sample_fmtbit(it.handle, &mask.formats);
869 else if (consume_string(handle, "AudioChannelLayoutElements"))
870 ret = parse_nchans_mask(it.handle, &mask.nchans);
871 else
872 ret = skip_pair(it.handle);
873
874 if (ret)
875 return ret;
876 }
877
878 trace_avep_sound_mode(handle->dcp, mask.rates, mask.formats, mask.nchans);
879
880 if (!(mask.rates & sieve->rates) || !(mask.formats & sieve->formats) ||
881 !(mask.nchans & sieve->nchans))
882 return 0;
883
884 if (hits) {
885 hits->rates |= mask.rates;
886 hits->formats |= mask.formats;
887 hits->nchans |= mask.nchans;
888 }
889
890 return 1;
891 }
892
parse_mode_in_avep_element(struct dcp_parse_ctx * handle,unsigned int selected_nchans,struct snd_pcm_chmap_elem * chmap,struct dcp_sound_cookie * cookie)893 static int parse_mode_in_avep_element(struct dcp_parse_ctx *handle,
894 unsigned int selected_nchans,
895 struct snd_pcm_chmap_elem *chmap,
896 struct dcp_sound_cookie *cookie)
897 {
898 struct iterator it;
899 struct dcp_parse_ctx save_handle;
900 int ret;
901
902 dcp_parse_foreach_in_dict(handle, it) {
903 if (consume_string(it.handle, "AudioChannelLayoutElements")) {
904 struct iterator inner_it;
905 int nchans;
906
907 dcp_parse_foreach_in_array(it.handle, inner_it) {
908 save_handle = *it.handle;
909 ret = parse_chan_layout_element(inner_it.handle,
910 &nchans, NULL);
911 if (ret)
912 return ret;
913
914 if (nchans != selected_nchans)
915 continue;
916
917 /*
918 * Now that we know this layout matches the
919 * selected channel number, reread the element
920 * and fill in the channel map.
921 */
922 *inner_it.handle = save_handle;
923 ret = parse_chan_layout_element(inner_it.handle,
924 NULL, chmap);
925 if (ret)
926 return ret;
927 }
928 } else if (consume_string(it.handle, "ElementData")) {
929 const u8 *blob;
930
931 ret = parse_blob(it.handle, sizeof(*cookie), &blob);
932 if (ret)
933 return ret;
934
935 if (cookie)
936 memcpy(cookie, blob, sizeof(*cookie));
937 } else {
938 ret = skip_pair(it.handle);
939 if (ret)
940 return ret;
941 }
942 }
943
944 return 0;
945 }
946
parse_sound_constraints(struct dcp_parse_ctx * handle,struct dcp_sound_format_mask * sieve,struct dcp_sound_format_mask * hits)947 int parse_sound_constraints(struct dcp_parse_ctx *handle,
948 struct dcp_sound_format_mask *sieve,
949 struct dcp_sound_format_mask *hits)
950 {
951 int ret;
952 struct iterator it;
953
954 if (hits) {
955 hits->rates = 0;
956 hits->formats = 0;
957 hits->nchans = 0;
958 }
959
960 dcp_parse_foreach_in_array(handle, it) {
961 ret = parse_avep_element(it.handle, sieve, hits);
962
963 if (ret < 0)
964 return ret;
965 }
966
967 return 0;
968 }
969 EXPORT_SYMBOL_GPL(parse_sound_constraints);
970
parse_sound_mode(struct dcp_parse_ctx * handle,struct dcp_sound_format_mask * sieve,struct snd_pcm_chmap_elem * chmap,struct dcp_sound_cookie * cookie)971 int parse_sound_mode(struct dcp_parse_ctx *handle,
972 struct dcp_sound_format_mask *sieve,
973 struct snd_pcm_chmap_elem *chmap,
974 struct dcp_sound_cookie *cookie)
975 {
976 struct dcp_parse_ctx save_handle;
977 struct iterator it;
978 int ret;
979
980 dcp_parse_foreach_in_array(handle, it) {
981 save_handle = *it.handle;
982 ret = parse_avep_element(it.handle, sieve, NULL);
983
984 if (!ret)
985 continue;
986
987 if (ret < 0)
988 return ret;
989
990 ret = parse_mode_in_avep_element(&save_handle, __ffs(sieve->nchans),
991 chmap, cookie);
992 if (ret < 0)
993 return ret;
994 return 1;
995 }
996
997 return 0;
998 }
999 EXPORT_SYMBOL_GPL(parse_sound_mode);
1000
parse_system_log_mnits(struct dcp_parse_ctx * handle,struct dcp_system_ev_mnits * entry)1001 int parse_system_log_mnits(struct dcp_parse_ctx *handle, struct dcp_system_ev_mnits *entry)
1002 {
1003 struct iterator it;
1004 int ret;
1005 s64 mnits = -1;
1006 s64 idac = -1;
1007 s64 timestamp = -1;
1008 bool type_match = false;
1009
1010 dcp_parse_foreach_in_dict(handle, it) {
1011 char *key = parse_string(it.handle);
1012 if (IS_ERR(key)) {
1013 ret = PTR_ERR(key);
1014 } else if (!strcmp(key, "mNits")) {
1015 ret = parse_int(it.handle, &mnits);
1016 } else if (!strcmp(key, "iDAC")) {
1017 ret = parse_int(it.handle, &idac);
1018 } else if (!strcmp(key, "logEvent")) {
1019 const char * value = parse_string(it.handle);
1020 if (!IS_ERR_OR_NULL(value)) {
1021 type_match = strcmp(value, "Display (Event Forward)") == 0;
1022 kfree(value);
1023 }
1024 } else if (!strcmp(key, "timestamp")) {
1025 ret = parse_int(it.handle, ×tamp);
1026 } else {
1027 skip(it.handle);
1028 }
1029
1030 if (!IS_ERR_OR_NULL(key))
1031 kfree(key);
1032
1033 if (ret) {
1034 pr_err("dcp parser: failed to parse mNits sys event\n");
1035 return ret;
1036 }
1037 }
1038
1039 if (!type_match || mnits < 0 || idac < 0 || timestamp < 0)
1040 return -EINVAL;
1041
1042 entry->millinits = mnits;
1043 entry->idac = idac;
1044 entry->timestamp = timestamp;
1045
1046 return 0;
1047 }
1048