Line data Source code
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 const struct displayid_header *
11 : displayid_get_header(const u8 *displayid, int length, int index)
12 : {
13 : const struct displayid_header *base;
14 :
15 0 : if (sizeof(*base) > length - index)
16 : return ERR_PTR(-EINVAL);
17 :
18 0 : base = (const struct displayid_header *)&displayid[index];
19 :
20 : return base;
21 : }
22 :
23 : static const struct displayid_header *
24 0 : validate_displayid(const u8 *displayid, int length, int idx)
25 : {
26 : int i, dispid_length;
27 0 : u8 csum = 0;
28 : const struct displayid_header *base;
29 :
30 0 : base = displayid_get_header(displayid, length, idx);
31 0 : if (IS_ERR(base))
32 : return base;
33 :
34 0 : DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n",
35 : base->rev, base->bytes, base->prod_id, base->ext_count);
36 :
37 : /* +1 for DispID checksum */
38 0 : dispid_length = sizeof(*base) + base->bytes + 1;
39 0 : if (dispid_length > length - idx)
40 : return ERR_PTR(-EINVAL);
41 :
42 0 : for (i = 0; i < dispid_length; i++)
43 0 : csum += displayid[idx + i];
44 0 : if (csum) {
45 0 : DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum);
46 0 : return ERR_PTR(-EINVAL);
47 : }
48 :
49 : return base;
50 : }
51 :
52 0 : static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid,
53 : int *length, int *idx,
54 : int *ext_index)
55 : {
56 0 : const u8 *displayid = drm_find_edid_extension(drm_edid, DISPLAYID_EXT, ext_index);
57 : const struct displayid_header *base;
58 :
59 0 : if (!displayid)
60 : return NULL;
61 :
62 : /* EDID extensions block checksum isn't for us */
63 0 : *length = EDID_LENGTH - 1;
64 0 : *idx = 1;
65 :
66 0 : base = validate_displayid(displayid, *length, *idx);
67 0 : if (IS_ERR(base))
68 : return NULL;
69 :
70 0 : *length = *idx + sizeof(*base) + base->bytes;
71 :
72 0 : return displayid;
73 : }
74 :
75 0 : void displayid_iter_edid_begin(const struct drm_edid *drm_edid,
76 : struct displayid_iter *iter)
77 : {
78 0 : memset(iter, 0, sizeof(*iter));
79 :
80 0 : iter->drm_edid = drm_edid;
81 0 : }
82 :
83 : static const struct displayid_block *
84 : displayid_iter_block(const struct displayid_iter *iter)
85 : {
86 : const struct displayid_block *block;
87 :
88 0 : if (!iter->section)
89 : return NULL;
90 :
91 0 : block = (const struct displayid_block *)&iter->section[iter->idx];
92 :
93 0 : if (iter->idx + sizeof(*block) <= iter->length &&
94 0 : iter->idx + sizeof(*block) + block->num_bytes <= iter->length)
95 : return block;
96 :
97 : return NULL;
98 : }
99 :
100 : const struct displayid_block *
101 0 : __displayid_iter_next(struct displayid_iter *iter)
102 : {
103 : const struct displayid_block *block;
104 :
105 0 : if (!iter->drm_edid)
106 : return NULL;
107 :
108 0 : if (iter->section) {
109 : /* current block should always be valid */
110 0 : block = displayid_iter_block(iter);
111 0 : if (WARN_ON(!block)) {
112 0 : iter->section = NULL;
113 0 : iter->drm_edid = NULL;
114 0 : return NULL;
115 : }
116 :
117 : /* next block in section */
118 0 : iter->idx += sizeof(*block) + block->num_bytes;
119 :
120 0 : block = displayid_iter_block(iter);
121 0 : if (block)
122 : return block;
123 : }
124 :
125 : for (;;) {
126 : /* The first section we encounter is the base section */
127 0 : bool base_section = !iter->section;
128 :
129 0 : iter->section = drm_find_displayid_extension(iter->drm_edid,
130 : &iter->length,
131 : &iter->idx,
132 : &iter->ext_index);
133 0 : if (!iter->section) {
134 0 : iter->drm_edid = NULL;
135 0 : return NULL;
136 : }
137 :
138 : /* Save the structure version and primary use case. */
139 0 : if (base_section) {
140 : const struct displayid_header *base;
141 :
142 0 : base = displayid_get_header(iter->section, iter->length,
143 : iter->idx);
144 0 : if (!IS_ERR(base)) {
145 0 : iter->version = base->rev;
146 0 : iter->primary_use = base->prod_id;
147 : }
148 : }
149 :
150 0 : iter->idx += sizeof(struct displayid_header);
151 :
152 0 : block = displayid_iter_block(iter);
153 0 : if (block)
154 : return block;
155 : }
156 : }
157 :
158 0 : void displayid_iter_end(struct displayid_iter *iter)
159 : {
160 0 : memset(iter, 0, sizeof(*iter));
161 0 : }
162 :
163 : /* DisplayID Structure Version/Revision from the Base Section. */
164 0 : u8 displayid_version(const struct displayid_iter *iter)
165 : {
166 0 : return iter->version;
167 : }
168 :
169 : /*
170 : * DisplayID Primary Use Case (2.0+) or Product Type Identifier (1.0-1.3) from
171 : * the Base Section.
172 : */
173 0 : u8 displayid_primary_use(const struct displayid_iter *iter)
174 : {
175 0 : return iter->primary_use;
176 : }
|