diff options
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 65 | ||||
-rw-r--r-- | include/drm/drm_edid.h | 9 |
2 files changed, 74 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index ecd6e9255b67..8fed2131f424 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -102,6 +102,11 @@ struct detailed_mode_closure { int modes; }; +struct drm_edid_match_closure { + const struct drm_edid_ident *ident; + bool matched; +}; + #define LEVEL_DMT 0 #define LEVEL_GTF 1 #define LEVEL_GTF2 2 @@ -5456,6 +5461,66 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db) } static void +match_identity(const struct detailed_timing *timing, void *data) +{ + struct drm_edid_match_closure *closure = data; + unsigned int i; + const char *name = closure->ident->name; + unsigned int name_len = strlen(name); + const char *desc = timing->data.other_data.data.str.str; + unsigned int desc_len = ARRAY_SIZE(timing->data.other_data.data.str.str); + + if (name_len > desc_len || + !(is_display_descriptor(timing, EDID_DETAIL_MONITOR_NAME) || + is_display_descriptor(timing, EDID_DETAIL_MONITOR_STRING))) + return; + + if (strncmp(name, desc, name_len)) + return; + + for (i = name_len; i < desc_len; i++) { + if (desc[i] == '\n') + break; + /* Allow white space before EDID string terminator. */ + if (!isspace(desc[i])) + return; + } + + closure->matched = true; +} + +/** + * drm_edid_match - match drm_edid with given identity + * @drm_edid: EDID + * @ident: the EDID identity to match with + * + * Check if the EDID matches with the given identity. + * + * Return: True if the given identity matched with EDID, false otherwise. + */ +bool drm_edid_match(const struct drm_edid *drm_edid, + const struct drm_edid_ident *ident) +{ + if (!drm_edid || drm_edid_get_panel_id(drm_edid) != ident->panel_id) + return false; + + /* Match with name only if it's not NULL. */ + if (ident->name) { + struct drm_edid_match_closure closure = { + .ident = ident, + .matched = false, + }; + + drm_for_each_detailed_block(drm_edid, match_identity, &closure); + + return closure.matched; + } + + return true; +} +EXPORT_SYMBOL(drm_edid_match); + +static void monitor_name(const struct detailed_timing *timing, void *data) { const char **res = data; diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 9686a7cee6a6..6f65bbf655a1 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -312,6 +312,13 @@ struct edid { u8 checksum; } __packed; +/* EDID matching */ +struct drm_edid_ident { + /* ID encoded by drm_edid_encode_panel_id() */ + u32 panel_id; + const char *name; +}; + #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) /* Short Audio Descriptor */ @@ -412,6 +419,8 @@ struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); const struct drm_edid *drm_edid_read_base_block(struct i2c_adapter *adapter); u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid); +bool drm_edid_match(const struct drm_edid *drm_edid, + const struct drm_edid_ident *ident); struct edid *drm_get_edid_switcheroo(struct drm_connector *connector, struct i2c_adapter *adapter); struct edid *drm_edid_duplicate(const struct edid *edid); |