Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright © 2021 Intel Corporation
0004  */
0005 
0006 #include <drm/drm_displayid.h>
0007 #include <drm/drm_edid.h>
0008 #include <drm/drm_print.h>
0009 
0010 static int validate_displayid(const u8 *displayid, int length, int idx)
0011 {
0012     int i, dispid_length;
0013     u8 csum = 0;
0014     const struct displayid_header *base;
0015 
0016     base = (const struct displayid_header *)&displayid[idx];
0017 
0018     DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n",
0019               base->rev, base->bytes, base->prod_id, base->ext_count);
0020 
0021     /* +1 for DispID checksum */
0022     dispid_length = sizeof(*base) + base->bytes + 1;
0023     if (dispid_length > length - idx)
0024         return -EINVAL;
0025 
0026     for (i = 0; i < dispid_length; i++)
0027         csum += displayid[idx + i];
0028     if (csum) {
0029         DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum);
0030         return -EINVAL;
0031     }
0032 
0033     return 0;
0034 }
0035 
0036 static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid,
0037                           int *length, int *idx,
0038                           int *ext_index)
0039 {
0040     const u8 *displayid = drm_find_edid_extension(drm_edid, DISPLAYID_EXT, ext_index);
0041     const struct displayid_header *base;
0042     int ret;
0043 
0044     if (!displayid)
0045         return NULL;
0046 
0047     /* EDID extensions block checksum isn't for us */
0048     *length = EDID_LENGTH - 1;
0049     *idx = 1;
0050 
0051     ret = validate_displayid(displayid, *length, *idx);
0052     if (ret)
0053         return NULL;
0054 
0055     base = (const struct displayid_header *)&displayid[*idx];
0056     *length = *idx + sizeof(*base) + base->bytes;
0057 
0058     return displayid;
0059 }
0060 
0061 void displayid_iter_edid_begin(const struct drm_edid *drm_edid,
0062                    struct displayid_iter *iter)
0063 {
0064     memset(iter, 0, sizeof(*iter));
0065 
0066     iter->drm_edid = drm_edid;
0067 }
0068 
0069 static const struct displayid_block *
0070 displayid_iter_block(const struct displayid_iter *iter)
0071 {
0072     const struct displayid_block *block;
0073 
0074     if (!iter->section)
0075         return NULL;
0076 
0077     block = (const struct displayid_block *)&iter->section[iter->idx];
0078 
0079     if (iter->idx + sizeof(*block) <= iter->length &&
0080         iter->idx + sizeof(*block) + block->num_bytes <= iter->length)
0081         return block;
0082 
0083     return NULL;
0084 }
0085 
0086 const struct displayid_block *
0087 __displayid_iter_next(struct displayid_iter *iter)
0088 {
0089     const struct displayid_block *block;
0090 
0091     if (!iter->drm_edid)
0092         return NULL;
0093 
0094     if (iter->section) {
0095         /* current block should always be valid */
0096         block = displayid_iter_block(iter);
0097         if (WARN_ON(!block)) {
0098             iter->section = NULL;
0099             iter->drm_edid = NULL;
0100             return NULL;
0101         }
0102 
0103         /* next block in section */
0104         iter->idx += sizeof(*block) + block->num_bytes;
0105 
0106         block = displayid_iter_block(iter);
0107         if (block)
0108             return block;
0109     }
0110 
0111     for (;;) {
0112         iter->section = drm_find_displayid_extension(iter->drm_edid,
0113                                  &iter->length,
0114                                  &iter->idx,
0115                                  &iter->ext_index);
0116         if (!iter->section) {
0117             iter->drm_edid = NULL;
0118             return NULL;
0119         }
0120 
0121         iter->idx += sizeof(struct displayid_header);
0122 
0123         block = displayid_iter_block(iter);
0124         if (block)
0125             return block;
0126     }
0127 }
0128 
0129 void displayid_iter_end(struct displayid_iter *iter)
0130 {
0131     memset(iter, 0, sizeof(*iter));
0132 }