/** * drm_edid_is_valid - sanity check EDID data * @edid: EDID data * * Sanity-check an entire EDID record (including extensions) */ bool drm_edid_is_valid(struct edid *edid) { int i; u8 *raw = (u8 *)edid; if (!edid) return false; for (i = 0; i <= edid->extensions; i++) if (!drm_edid_block_valid(raw + i * EDID_LENGTH)) return false; return true; }
static int edid_load(struct drm_connector *connector, char *name, char *connector_name) { const struct firmware *fw; struct platform_device *pdev; u8 *fwdata = NULL, *edid; int fwsize, expected; int builtin = 0, err = 0; int i, valid_extensions = 0; pdev = platform_device_register_simple(connector_name, -1, NULL, 0); if (IS_ERR(pdev)) { DRM_ERROR("Failed to register EDID firmware platform device " "for connector \"%s\"\n", connector_name); err = -EINVAL; goto out; } err = request_firmware(&fw, name, &pdev->dev); platform_device_unregister(pdev); if (err) { i = 0; while (i < GENERIC_EDIDS && strcmp(name, generic_edid_name[i])) i++; if (i < GENERIC_EDIDS) { err = 0; builtin = 1; fwdata = generic_edid[i]; fwsize = sizeof(generic_edid[i]); } } if (err) { DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n", name, err); goto out; } if (fwdata == NULL) { fwdata = (u8 *) fw->data; fwsize = fw->size; } expected = (fwdata[0x7e] + 1) * EDID_LENGTH; if (expected != fwsize) { DRM_ERROR("Size of EDID firmware \"%s\" is invalid " "(expected %d, got %d)\n", name, expected, (int) fwsize); err = -EINVAL; goto relfw_out; } edid = kmalloc(fwsize, GFP_KERNEL); if (edid == NULL) { err = -ENOMEM; goto relfw_out; } memcpy(edid, fwdata, fwsize); if (!drm_edid_block_valid(edid)) { DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ", name); kfree(edid); err = -EINVAL; goto relfw_out; } for (i = 1; i <= edid[0x7e]; i++) { 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)) valid_extensions++; } if (valid_extensions != edid[0x7e]) { edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions; DRM_INFO("Found %d valid extensions instead of %d in EDID data " "\"%s\" for connector \"%s\"\n", valid_extensions, edid[0x7e], name, connector_name); edid[0x7e] = valid_extensions; edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL); if (edid == NULL) { err = -ENOMEM; goto relfw_out; } } connector->display_info.raw_edid = edid; DRM_INFO("Got %s EDID base block and %d extension%s from " "\"%s\" for connector \"%s\"\n", builtin ? "built-in" : "external", valid_extensions, valid_extensions == 1 ? "" : "s", name, connector_name); relfw_out: release_firmware(fw); out: return err; }
static u8 *edid_load(struct drm_connector *connector, const char *name, const char *connector_name) { const struct firmware *fw = NULL; const u8 *fwdata; u8 *edid; int fwsize, builtin; int i, valid_extensions = 0; bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS); builtin = 0; for (i = 0; i < GENERIC_EDIDS; i++) { if (strcmp(name, generic_edid_name[i]) == 0) { fwdata = generic_edid[i]; fwsize = sizeof(generic_edid[i]); builtin = 1; break; } } if (!builtin) { struct platform_device *pdev; int err; pdev = platform_device_register_simple(connector_name, -1, NULL, 0); if (IS_ERR(pdev)) { DRM_ERROR("Failed to register EDID firmware platform device " "for connector \"%s\"\n", connector_name); return ERR_CAST(pdev); } err = request_firmware(&fw, name, &pdev->dev); platform_device_unregister(pdev); if (err) { DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n", name, err); return ERR_PTR(err); } fwdata = fw->data; fwsize = fw->size; } if (edid_size(fwdata, fwsize) != fwsize) { DRM_ERROR("Size of EDID firmware \"%s\" is invalid " "(expected %d, got %d\n", name, edid_size(fwdata, fwsize), (int)fwsize); edid = ERR_PTR(-EINVAL); goto out; } edid = kmemdup(fwdata, fwsize, GFP_KERNEL); if (edid == NULL) { edid = ERR_PTR(-ENOMEM); goto out; } if (!drm_edid_block_valid(edid, 0, print_bad_edid)) { connector->bad_edid_counter++; DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ", name); kfree(edid); edid = ERR_PTR(-EINVAL); goto out; } for (i = 1; i <= edid[0x7e]; i++) { 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)) valid_extensions++; } if (valid_extensions != edid[0x7e]) { u8 *new_edid; edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions; DRM_INFO("Found %d valid extensions instead of %d in EDID data " "\"%s\" for connector \"%s\"\n", valid_extensions, edid[0x7e], name, connector_name); edid[0x7e] = valid_extensions; new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL); if (new_edid) edid = new_edid; } DRM_INFO("Got %s EDID base block and %d extension%s from " "\"%s\" for connector \"%s\"\n", builtin ? "built-in" : "external", valid_extensions, valid_extensions == 1 ? "" : "s", name, connector_name); out: if (fw) release_firmware(fw); return edid; }