xref: /openbsd/sys/dev/pci/drm/apple/parser.c (revision a5620f7a)
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, &timestamp);
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