--- drivers/gpu/drm/drm_crtc_helper.c | 7 ++++ drivers/gpu/drm/drm_edid.c | 5 +++ drivers/gpu/drm/drm_sysfs.c | 63 +++++++++++++++++++++++++++++++++++++- include/drm/drm_crtc.h | 1 4 files changed, 75 insertions(+), 1 deletion(-) Index: 2.6.33/drivers/gpu/drm/drm_crtc_helper.c =================================================================== --- 2.6.33.orig/drivers/gpu/drm/drm_crtc_helper.c +++ 2.6.33/drivers/gpu/drm/drm_crtc_helper.c @@ -87,6 +87,13 @@ int drm_helper_probe_single_connector_mo int mode_flags = 0; DRM_DEBUG_KMS("%s\n", drm_get_connector_name(connector)); + + if (connector->edid_pinned) { + list_for_each_entry(mode, &connector->modes, head) + count++; + return count; + } + /* set all modes to the unverified state */ list_for_each_entry_safe(mode, t, &connector->modes, head) mode->status = MODE_UNVERIFIED; Index: 2.6.33/drivers/gpu/drm/drm_edid.c =================================================================== --- 2.6.33.orig/drivers/gpu/drm/drm_edid.c +++ 2.6.33/drivers/gpu/drm/drm_edid.c @@ -1213,6 +1213,11 @@ struct edid *drm_get_edid(struct drm_con int ret; struct edid *edid; + if (connector->edid_pinned) { + edid = (struct edid *) connector->display_info.raw_edid; + goto end; + } + edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1), GFP_KERNEL); if (edid == NULL) { Index: 2.6.33/drivers/gpu/drm/drm_sysfs.c =================================================================== --- 2.6.33.orig/drivers/gpu/drm/drm_sysfs.c +++ 2.6.33/drivers/gpu/drm/drm_sysfs.c @@ -15,9 +15,11 @@ #include #include #include +#include #include "drm_sysfs.h" #include "drm_core.h" +#include "drm_edid.h" #include "drmP.h" #define to_drm_minor(d) container_of(d, struct drm_minor, kdev) @@ -220,6 +222,64 @@ static ssize_t edid_show(struct kobject return count; } +static ssize_t edid_store(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *connector_dev = container_of(kobj, struct device, kobj); + struct drm_connector *connector = to_drm_connector(connector_dev); + const struct firmware *fw; + unsigned char *edid; + size_t size = EDID_LENGTH; + int status; + char *filename, *cr; + + if (count == 0 || *buf == '\n' || *buf == '\0') { + connector->edid_pinned = 0; + return count; + } + + filename = kmalloc(count+1, GFP_KERNEL); + if (!filename) + return -ENOMEM; + memcpy(filename, buf, count); + filename[count] = '\0'; + + cr = strchr(filename, '\n'); + if (cr) + *cr = '\0'; + + status = request_firmware(&fw, filename, connector_dev); + kfree(filename); + if (status) + return status; + + if (fw->size != size) { + release_firmware(fw); + return -EINVAL; + } + + edid = kmalloc(size, GFP_KERNEL); + if (edid == NULL) { + release_firmware(fw); + return -ENOMEM; + } + + edid = (unsigned char *) fw->data; + + drm_mode_connector_update_edid_property(connector, + (struct edid *) edid); + drm_add_edid_modes(connector, (struct edid *) edid); + drm_mode_connector_list_update(connector); + drm_mode_sort(&connector->modes); + + connector->display_info.raw_edid = edid; + connector->edid_pinned = 1; + + release_firmware(fw); + + return count; +} + static ssize_t modes_show(struct device *device, struct device_attribute *attr, char *buf) @@ -333,9 +393,10 @@ static struct device_attribute connector static struct bin_attribute edid_attr = { .attr.name = "edid", - .attr.mode = 0444, + .attr.mode = 0644, .size = 128, .read = edid_show, + .write = edid_store, }; /** Index: 2.6.33/include/drm/drm_crtc.h =================================================================== --- 2.6.33.orig/include/drm/drm_crtc.h +++ 2.6.33/include/drm/drm_crtc.h @@ -508,6 +508,7 @@ struct drm_connector { struct list_head user_modes; struct drm_property_blob *edid_blob_ptr; + int edid_pinned; u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY]; uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY];