FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > Ubuntu > Ubuntu Kernel Team

 
 
LinkBack Thread Tools
 
Old 03-21-2012, 02:58 PM
Andy Whitcroft
 
Default drm/edid: allow to load edid firmware

From: Carsten Emde <C.Emde@osadl.org>

Use the firmware interface to load binary EDID data from
a file and use them to assign monitor data to a video
connector. EDID data is located in the edid/ directory within
the existing firmware directories.

[apw@canonical.com: follow the changes to the sysfs interfaces]
[apw@canonical.com: fix the memory allocation so we use the real buffer]
[apw@canonical.com: add a firware prefix edid/ to limit what may be loaded]
Signed-off-by: Carsten Emde <C.Emde@osadl.org>
Signed-off-by: Andy Whitcroft <apw@canonical.com>
---
drivers/gpu/drm/drm_crtc_helper.c | 7 ++++
drivers/gpu/drm/drm_edid.c | 5 +++
drivers/gpu/drm/drm_sysfs.c | 66 ++++++++++++++++++++++++++++++++++++-
include/drm/drm_crtc.h | 1 +
4 files changed, 78 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index d2619d7..8dd1680 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -94,6 +94,13 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,

DRM_DEBUG_KMS("[CONNECTOR:%d:%s]
", connector->base.id,
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;
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index fb6c26c..1944fd5 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -385,6 +385,11 @@ struct edid *drm_get_edid(struct drm_connector *connector,
{
struct edid *edid = NULL;

+ if (connector->edid_pinned) {
+ edid = (struct edid *) connector->display_info.raw_edid;
+ return edid;
+ }
+
if (drm_probe_ddc(adapter))
edid = (struct edid *)drm_do_get_edid(connector, adapter);

diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 0f9ef9b..c5c875d 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -17,9 +17,11 @@
#include <linux/gfp.h>
#include <linux/err.h>
#include <linux/export.h>
+#include <linux/firmware.h>

#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)
@@ -228,6 +230,67 @@ static ssize_t edid_show(struct file *filp, struct kobject *kobj,
return count;
}

+#define EDID_FIRMWARE_PREFIX "edid/"
+
+static ssize_t edid_store(struct file *file, 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 == '
' || *buf == '') {
+ connector->edid_pinned = 0;
+ return count;
+ }
+
+ filename = kmalloc(sizeof(EDID_FIRMWARE_PREFIX) + count, GFP_KERNEL);
+ if (!filename)
+ return -ENOMEM;
+ strcpy(filename, EDID_FIRMWARE_PREFIX);
+ memcpy(filename + sizeof(EDID_FIRMWARE_PREFIX) - 1, buf, count);
+ filename[sizeof(EDID_FIRMWARE_PREFIX) + count] = '';
+
+ cr = strchr(filename, '
');
+ if (cr)
+ *cr = '';
+
+ 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;
+ }
+
+ memcpy(edid, fw->data, size);
+
+ 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)
@@ -341,9 +404,10 @@ static struct device_attribute connector_attrs_opt1[] = {

static struct bin_attribute edid_attr = {
.attr.name = "edid",
- .attr.mode = 0444,
+ .attr.mode = 0644,
.size = 0,
.read = edid_show,
+ .write = edid_store,
};

/**
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 8020798..96d6e18 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -509,6 +509,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];

--
1.7.9.1


--
kernel-team mailing list
kernel-team@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/kernel-team
 

Thread Tools




All times are GMT. The time now is 05:24 AM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org