177 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2021 Intel Corporation4 */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 12static const struct displayid_header *13displayid_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 25static const struct displayid_header *26validate_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 51static 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 75void 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 83static const struct displayid_block *84displayid_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 100const 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 158void 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. */164u8 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) from171 * the Base Section.172 */173u8 displayid_primary_use(const struct displayid_iter *iter)174{175 return iter->primary_use;176}177