Line data Source code
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 0 : static int validate_displayid(const u8 *displayid, int length, int idx) 11 : { 12 : int i, dispid_length; 13 0 : u8 csum = 0; 14 : const struct displayid_header *base; 15 : 16 0 : base = (const struct displayid_header *)&displayid[idx]; 17 : 18 0 : DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n", 19 : base->rev, base->bytes, base->prod_id, base->ext_count); 20 : 21 : /* +1 for DispID checksum */ 22 0 : dispid_length = sizeof(*base) + base->bytes + 1; 23 0 : if (dispid_length > length - idx) 24 : return -EINVAL; 25 : 26 0 : for (i = 0; i < dispid_length; i++) 27 0 : csum += displayid[idx + i]; 28 0 : if (csum) { 29 0 : DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum); 30 0 : return -EINVAL; 31 : } 32 : 33 : return 0; 34 : } 35 : 36 0 : static const u8 *drm_find_displayid_extension(const struct edid *edid, 37 : int *length, int *idx, 38 : int *ext_index) 39 : { 40 0 : const u8 *displayid = drm_find_edid_extension(edid, DISPLAYID_EXT, ext_index); 41 : const struct displayid_header *base; 42 : int ret; 43 : 44 0 : if (!displayid) 45 : return NULL; 46 : 47 : /* EDID extensions block checksum isn't for us */ 48 0 : *length = EDID_LENGTH - 1; 49 0 : *idx = 1; 50 : 51 0 : ret = validate_displayid(displayid, *length, *idx); 52 0 : if (ret) 53 : return NULL; 54 : 55 0 : base = (const struct displayid_header *)&displayid[*idx]; 56 0 : *length = *idx + sizeof(*base) + base->bytes; 57 : 58 0 : return displayid; 59 : } 60 : 61 0 : void displayid_iter_edid_begin(const struct edid *edid, 62 : struct displayid_iter *iter) 63 : { 64 0 : memset(iter, 0, sizeof(*iter)); 65 : 66 0 : iter->edid = edid; 67 0 : } 68 : 69 : static const struct displayid_block * 70 : displayid_iter_block(const struct displayid_iter *iter) 71 : { 72 : const struct displayid_block *block; 73 : 74 0 : if (!iter->section) 75 : return NULL; 76 : 77 0 : block = (const struct displayid_block *)&iter->section[iter->idx]; 78 : 79 0 : if (iter->idx + sizeof(*block) <= iter->length && 80 0 : iter->idx + sizeof(*block) + block->num_bytes <= iter->length) 81 : return block; 82 : 83 : return NULL; 84 : } 85 : 86 : const struct displayid_block * 87 0 : __displayid_iter_next(struct displayid_iter *iter) 88 : { 89 : const struct displayid_block *block; 90 : 91 0 : if (!iter->edid) 92 : return NULL; 93 : 94 0 : if (iter->section) { 95 : /* current block should always be valid */ 96 0 : block = displayid_iter_block(iter); 97 0 : if (WARN_ON(!block)) { 98 0 : iter->section = NULL; 99 0 : iter->edid = NULL; 100 0 : return NULL; 101 : } 102 : 103 : /* next block in section */ 104 0 : iter->idx += sizeof(*block) + block->num_bytes; 105 : 106 0 : block = displayid_iter_block(iter); 107 0 : if (block) 108 : return block; 109 : } 110 : 111 : for (;;) { 112 0 : iter->section = drm_find_displayid_extension(iter->edid, 113 : &iter->length, 114 : &iter->idx, 115 : &iter->ext_index); 116 0 : if (!iter->section) { 117 0 : iter->edid = NULL; 118 0 : return NULL; 119 : } 120 : 121 0 : iter->idx += sizeof(struct displayid_header); 122 : 123 0 : block = displayid_iter_block(iter); 124 0 : if (block) 125 : return block; 126 : } 127 : } 128 : 129 0 : void displayid_iter_end(struct displayid_iter *iter) 130 : { 131 0 : memset(iter, 0, sizeof(*iter)); 132 0 : }