summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/gpu/drm/drm_edid_load.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drivers/gpu/drm/drm_edid_load.c')
-rw-r--r--kernel/drivers/gpu/drm/drm_edid_load.c50
1 files changed, 39 insertions, 11 deletions
diff --git a/kernel/drivers/gpu/drm/drm_edid_load.c b/kernel/drivers/gpu/drm/drm_edid_load.c
index 4c0aa97aa..698b8c3b0 100644
--- a/kernel/drivers/gpu/drm/drm_edid_load.c
+++ b/kernel/drivers/gpu/drm/drm_edid_load.c
@@ -32,7 +32,7 @@ MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
"from built-in data or /lib/firmware instead. ");
#define GENERIC_EDIDS 6
-static const char *generic_edid_name[GENERIC_EDIDS] = {
+static const char * const generic_edid_name[GENERIC_EDIDS] = {
"edid/800x600.bin",
"edid/1024x768.bin",
"edid/1280x1024.bin",
@@ -216,7 +216,8 @@ static void *edid_load(struct drm_connector *connector, const char *name,
goto out;
}
- if (!drm_edid_block_valid(edid, 0, print_bad_edid)) {
+ if (!drm_edid_block_valid(edid, 0, print_bad_edid,
+ &connector->edid_corrupt)) {
connector->bad_edid_counter++;
DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
name);
@@ -229,7 +230,9 @@ static void *edid_load(struct drm_connector *connector, const char *name,
if (i != valid_extensions + 1)
memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
edid + i * EDID_LENGTH, EDID_LENGTH);
- if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, print_bad_edid))
+ if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
+ print_bad_edid,
+ NULL))
valid_extensions++;
}
@@ -261,20 +264,43 @@ out:
int drm_load_edid_firmware(struct drm_connector *connector)
{
const char *connector_name = connector->name;
- char *edidname = edid_firmware, *last, *colon;
+ char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
int ret;
struct edid *edid;
- if (*edidname == '\0')
+ if (edid_firmware[0] == '\0')
return 0;
- colon = strchr(edidname, ':');
- if (colon != NULL) {
- if (strncmp(connector_name, edidname, colon - edidname))
- return 0;
- edidname = colon + 1;
- if (*edidname == '\0')
+ /*
+ * If there are multiple edid files specified and separated
+ * by commas, search through the list looking for one that
+ * matches the connector.
+ *
+ * If there's one or more that don't't specify a connector, keep
+ * the last one found one as a fallback.
+ */
+ fwstr = kstrdup(edid_firmware, GFP_KERNEL);
+ edidstr = fwstr;
+
+ while ((edidname = strsep(&edidstr, ","))) {
+ colon = strchr(edidname, ':');
+ if (colon != NULL) {
+ if (strncmp(connector_name, edidname, colon - edidname))
+ continue;
+ edidname = colon + 1;
+ break;
+ }
+
+ if (*edidname != '\0') /* corner case: multiple ',' */
+ fallback = edidname;
+ }
+
+ if (!edidname) {
+ if (!fallback) {
+ kfree(fwstr);
return 0;
+ }
+ edidname = fallback;
}
last = edidname + strlen(edidname) - 1;
@@ -282,6 +308,8 @@ int drm_load_edid_firmware(struct drm_connector *connector)
*last = '\0';
edid = edid_load(connector, edidname, connector_name);
+ kfree(fwstr);
+
if (IS_ERR_OR_NULL(edid))
return 0;