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 int validate_displayid(const u8 *displayid, int length, int idx) 24 { 25 int i, dispid_length; 26 u8 csum = 0; 27 const struct displayid_header *base; 28 29 base = displayid_get_header(displayid, length, idx); 30 if (IS_ERR(base)) 31 return PTR_ERR(base); 32 33 DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n", 34 base->rev, base->bytes, base->prod_id, base->ext_count); 35 36 /* +1 for DispID checksum */ 37 dispid_length = sizeof(*base) + base->bytes + 1; 38 if (dispid_length > length - idx) 39 return -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 -EINVAL; 46 } 47 48 return 0; 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 u8 *displayid = drm_find_edid_extension(drm_edid, DISPLAYID_EXT, ext_index); 56 const struct displayid_header *base; 57 int ret; 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 ret = validate_displayid(displayid, *length, *idx); 67 if (ret) 68 return NULL; 69 70 base = (const struct displayid_header *)&displayid[*idx]; 71 *length = *idx + sizeof(*base) + base->bytes; 72 73 return displayid; 74 } 75 76 void displayid_iter_edid_begin(const struct drm_edid *drm_edid, 77 struct displayid_iter *iter) 78 { 79 memset(iter, 0, sizeof(*iter)); 80 81 iter->drm_edid = drm_edid; 82 } 83 84 static const struct displayid_block * 85 displayid_iter_block(const struct displayid_iter *iter) 86 { 87 const struct displayid_block *block; 88 89 if (!iter->section) 90 return NULL; 91 92 block = (const struct displayid_block *)&iter->section[iter->idx]; 93 94 if (iter->idx + sizeof(*block) <= iter->length && 95 iter->idx + sizeof(*block) + block->num_bytes <= iter->length) 96 return block; 97 98 return NULL; 99 } 100 101 const struct displayid_block * 102 __displayid_iter_next(struct displayid_iter *iter) 103 { 104 const struct displayid_block *block; 105 106 if (!iter->drm_edid) 107 return NULL; 108 109 if (iter->section) { 110 /* current block should always be valid */ 111 block = displayid_iter_block(iter); 112 if (WARN_ON(!block)) { 113 iter->section = NULL; 114 iter->drm_edid = NULL; 115 return NULL; 116 } 117 118 /* next block in section */ 119 iter->idx += sizeof(*block) + block->num_bytes; 120 121 block = displayid_iter_block(iter); 122 if (block) 123 return block; 124 } 125 126 for (;;) { 127 iter->section = drm_find_displayid_extension(iter->drm_edid, 128 &iter->length, 129 &iter->idx, 130 &iter->ext_index); 131 if (!iter->section) { 132 iter->drm_edid = NULL; 133 return NULL; 134 } 135 136 iter->idx += sizeof(struct displayid_header); 137 138 block = displayid_iter_block(iter); 139 if (block) 140 return block; 141 } 142 } 143 144 void displayid_iter_end(struct displayid_iter *iter) 145 { 146 memset(iter, 0, sizeof(*iter)); 147 } 148