Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright © 2021 Intel Corporation
  4 */
  5
  6#include <drm/drm_displayid.h>
  7#include <drm/drm_edid.h>
  8#include <drm/drm_print.h>
  9
 10static int validate_displayid(const u8 *displayid, int length, int idx)
 11{
 12	int i, dispid_length;
 13	u8 csum = 0;
 14	const struct displayid_header *base;
 15
 16	base = (const struct displayid_header *)&displayid[idx];
 17
 18	DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n",
 19		      base->rev, base->bytes, base->prod_id, base->ext_count);
 20
 21	/* +1 for DispID checksum */
 22	dispid_length = sizeof(*base) + base->bytes + 1;
 23	if (dispid_length > length - idx)
 24		return -EINVAL;
 25
 26	for (i = 0; i < dispid_length; i++)
 27		csum += displayid[idx + i];
 28	if (csum) {
 29		DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum);
 30		return -EINVAL;
 31	}
 32
 33	return 0;
 34}
 35
 36static const u8 *drm_find_displayid_extension(const struct edid *edid,
 37					      int *length, int *idx,
 38					      int *ext_index)
 39{
 40	const u8 *displayid = drm_find_edid_extension(edid, DISPLAYID_EXT, ext_index);
 41	const struct displayid_header *base;
 42	int ret;
 43
 44	if (!displayid)
 45		return NULL;
 46
 47	/* EDID extensions block checksum isn't for us */
 48	*length = EDID_LENGTH - 1;
 49	*idx = 1;
 50
 51	ret = validate_displayid(displayid, *length, *idx);
 52	if (ret)
 53		return NULL;
 54
 55	base = (const struct displayid_header *)&displayid[*idx];
 56	*length = *idx + sizeof(*base) + base->bytes;
 57
 58	return displayid;
 59}
 60
 61void displayid_iter_edid_begin(const struct edid *edid,
 62			       struct displayid_iter *iter)
 63{
 64	memset(iter, 0, sizeof(*iter));
 65
 66	iter->edid = edid;
 67}
 68
 69static const struct displayid_block *
 70displayid_iter_block(const struct displayid_iter *iter)
 71{
 72	const struct displayid_block *block;
 73
 74	if (!iter->section)
 75		return NULL;
 76
 77	block = (const struct displayid_block *)&iter->section[iter->idx];
 78
 79	if (iter->idx + sizeof(*block) <= iter->length &&
 80	    iter->idx + sizeof(*block) + block->num_bytes <= iter->length)
 81		return block;
 82
 83	return NULL;
 84}
 85
 86const struct displayid_block *
 87__displayid_iter_next(struct displayid_iter *iter)
 88{
 89	const struct displayid_block *block;
 90
 91	if (!iter->edid)
 92		return NULL;
 93
 94	if (iter->section) {
 95		/* current block should always be valid */
 96		block = displayid_iter_block(iter);
 97		if (WARN_ON(!block)) {
 98			iter->section = NULL;
 99			iter->edid = NULL;
100			return NULL;
101		}
102
103		/* next block in section */
104		iter->idx += sizeof(*block) + block->num_bytes;
105
106		block = displayid_iter_block(iter);
107		if (block)
108			return block;
109	}
110
111	for (;;) {
112		iter->section = drm_find_displayid_extension(iter->edid,
113							     &iter->length,
114							     &iter->idx,
115							     &iter->ext_index);
116		if (!iter->section) {
117			iter->edid = NULL;
118			return NULL;
119		}
120
121		iter->idx += sizeof(struct displayid_header);
122
123		block = displayid_iter_block(iter);
124		if (block)
125			return block;
126	}
127}
128
129void displayid_iter_end(struct displayid_iter *iter)
130{
131	memset(iter, 0, sizeof(*iter));
132}