Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/drm/drm_displayid.c
26444 views
1
// SPDX-License-Identifier: MIT
2
/*
3
* Copyright © 2021 Intel Corporation
4
*/
5
6
#include <drm/drm_edid.h>
7
#include <drm/drm_print.h>
8
9
#include "drm_crtc_internal.h"
10
#include "drm_displayid_internal.h"
11
12
static const struct displayid_header *
13
displayid_get_header(const u8 *displayid, int length, int index)
14
{
15
const struct displayid_header *base;
16
17
if (sizeof(*base) > length - index)
18
return ERR_PTR(-EINVAL);
19
20
base = (const struct displayid_header *)&displayid[index];
21
22
return base;
23
}
24
25
static const struct displayid_header *
26
validate_displayid(const u8 *displayid, int length, int idx)
27
{
28
int i, dispid_length;
29
u8 csum = 0;
30
const struct displayid_header *base;
31
32
base = displayid_get_header(displayid, length, idx);
33
if (IS_ERR(base))
34
return base;
35
36
/* +1 for DispID checksum */
37
dispid_length = sizeof(*base) + base->bytes + 1;
38
if (dispid_length > length - idx)
39
return ERR_PTR(-EINVAL);
40
41
for (i = 0; i < dispid_length; i++)
42
csum += displayid[idx + i];
43
if (csum) {
44
DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum);
45
return ERR_PTR(-EINVAL);
46
}
47
48
return base;
49
}
50
51
static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid,
52
int *length, int *idx,
53
int *ext_index)
54
{
55
const struct displayid_header *base;
56
const u8 *displayid;
57
58
displayid = drm_edid_find_extension(drm_edid, DISPLAYID_EXT, ext_index);
59
if (!displayid)
60
return NULL;
61
62
/* EDID extensions block checksum isn't for us */
63
*length = EDID_LENGTH - 1;
64
*idx = 1;
65
66
base = validate_displayid(displayid, *length, *idx);
67
if (IS_ERR(base))
68
return NULL;
69
70
*length = *idx + sizeof(*base) + base->bytes;
71
72
return displayid;
73
}
74
75
void displayid_iter_edid_begin(const struct drm_edid *drm_edid,
76
struct displayid_iter *iter)
77
{
78
memset(iter, 0, sizeof(*iter));
79
80
iter->drm_edid = drm_edid;
81
}
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
if (!iter->section)
89
return NULL;
90
91
block = (const struct displayid_block *)&iter->section[iter->idx];
92
93
if (iter->idx + sizeof(*block) <= iter->length &&
94
iter->idx + sizeof(*block) + block->num_bytes <= iter->length)
95
return block;
96
97
return NULL;
98
}
99
100
const struct displayid_block *
101
__displayid_iter_next(struct displayid_iter *iter)
102
{
103
const struct displayid_block *block;
104
105
if (!iter->drm_edid)
106
return NULL;
107
108
if (iter->section) {
109
/* current block should always be valid */
110
block = displayid_iter_block(iter);
111
if (WARN_ON(!block)) {
112
iter->section = NULL;
113
iter->drm_edid = NULL;
114
return NULL;
115
}
116
117
/* next block in section */
118
iter->idx += sizeof(*block) + block->num_bytes;
119
120
block = displayid_iter_block(iter);
121
if (block)
122
return block;
123
}
124
125
for (;;) {
126
/* The first section we encounter is the base section */
127
bool base_section = !iter->section;
128
129
iter->section = drm_find_displayid_extension(iter->drm_edid,
130
&iter->length,
131
&iter->idx,
132
&iter->ext_index);
133
if (!iter->section) {
134
iter->drm_edid = NULL;
135
return NULL;
136
}
137
138
/* Save the structure version and primary use case. */
139
if (base_section) {
140
const struct displayid_header *base;
141
142
base = displayid_get_header(iter->section, iter->length,
143
iter->idx);
144
if (!IS_ERR(base)) {
145
iter->version = base->rev;
146
iter->primary_use = base->prod_id;
147
}
148
}
149
150
iter->idx += sizeof(struct displayid_header);
151
152
block = displayid_iter_block(iter);
153
if (block)
154
return block;
155
}
156
}
157
158
void displayid_iter_end(struct displayid_iter *iter)
159
{
160
memset(iter, 0, sizeof(*iter));
161
}
162
163
/* DisplayID Structure Version/Revision from the Base Section. */
164
u8 displayid_version(const struct displayid_iter *iter)
165
{
166
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
u8 displayid_primary_use(const struct displayid_iter *iter)
174
{
175
return iter->primary_use;
176
}
177
178