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 if (sizeof(*base) > length - index) 16 return ERR_PTR(-EINVAL); 17 18 base = (const struct displayid_header *)&displayid[index]; 19 20 return base; 21 } 22 23 static const struct displayid_header * 24 validate_displayid(const u8 *displayid, int length, int idx) 25 { 26 int i, dispid_length; 27 u8 csum = 0; 28 const struct displayid_header *base; 29 30 base = displayid_get_header(displayid, length, idx); 31 if (IS_ERR(base)) 32 return base; 33 34 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 dispid_length = sizeof(*base) + base->bytes + 1; 39 if (dispid_length > length - idx) 40 return ERR_PTR(-EINVAL); 41 42 for (i = 0; i < dispid_length; i++) 43 csum += displayid[idx + i]; 44 if (csum) { 45 DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum); 46 return ERR_PTR(-EINVAL); 47 } 48 49 return base; 50 } 51 52 static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid, 53 int *length, int *idx, 54 int *ext_index) 55 { 56 const u8 *displayid = drm_find_edid_extension(drm_edid, DISPLAYID_EXT, ext_index); 57 const struct displayid_header *base; 58 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