Commit | Line | Data |
---|---|---|
4cc4f09e JN |
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 | ||
10 | static int validate_displayid(const u8 *displayid, int length, int idx) | |
11 | { | |
12 | int i, dispid_length; | |
13 | u8 csum = 0; | |
339be1a8 | 14 | const struct displayid_header *base; |
4cc4f09e | 15 | |
339be1a8 | 16 | base = (const struct displayid_header *)&displayid[idx]; |
4cc4f09e JN |
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 | ||
bfd4e192 JN |
36 | static const u8 *drm_find_displayid_extension(const struct edid *edid, |
37 | int *length, int *idx, | |
38 | int *ext_index) | |
4cc4f09e JN |
39 | { |
40 | const u8 *displayid = drm_find_edid_extension(edid, DISPLAYID_EXT, ext_index); | |
339be1a8 | 41 | const struct displayid_header *base; |
4cc4f09e JN |
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 | ||
339be1a8 | 55 | base = (const struct displayid_header *)&displayid[*idx]; |
4cc4f09e JN |
56 | *length = *idx + sizeof(*base) + base->bytes; |
57 | ||
58 | return displayid; | |
59 | } | |
1a24c364 JN |
60 | |
61 | void 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 | ||
69 | static const struct displayid_block * | |
70 | displayid_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 && | |
f72b1437 | 80 | iter->idx + sizeof(*block) + block->num_bytes <= iter->length) |
1a24c364 JN |
81 | return block; |
82 | ||
83 | return NULL; | |
84 | } | |
85 | ||
86 | const 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 | ||
339be1a8 | 121 | iter->idx += sizeof(struct displayid_header); |
1a24c364 JN |
122 | |
123 | block = displayid_iter_block(iter); | |
124 | if (block) | |
125 | return block; | |
126 | } | |
127 | } | |
128 | ||
129 | void displayid_iter_end(struct displayid_iter *iter) | |
130 | { | |
131 | memset(iter, 0, sizeof(*iter)); | |
132 | } |