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