These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / drm_edid_load.c
index 4c0aa97..698b8c3 100644 (file)
@@ -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;