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