drm/debugfs: add an "edid_override" file per connector
Add a file to debugfs for each connector to allow the EDID to be overridden. v2: Copy ubuf before accessing it and reject invalid length data. (David Herrmann) Ensure override_edid is reset when a new EDID value is written. (David Herrmann) Fix the debugfs file permissions. (David Herrmann) Signed-off-by: Thomas Wood <thomas.wood@intel.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Родитель
30f6570798
Коммит
4cf2b28146
|
@ -3763,6 +3763,10 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
|
|||
struct drm_device *dev = connector->dev;
|
||||
int ret, size;
|
||||
|
||||
/* ignore requests to set edid when overridden */
|
||||
if (connector->override_edid)
|
||||
return 0;
|
||||
|
||||
if (connector->edid_blob_ptr)
|
||||
drm_property_destroy_blob(dev, connector->edid_blob_ptr);
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
|
@ -304,6 +305,67 @@ static ssize_t connector_write(struct file *file, const char __user *ubuf,
|
|||
return len;
|
||||
}
|
||||
|
||||
static int edid_show(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_connector *connector = m->private;
|
||||
struct drm_property_blob *edid = connector->edid_blob_ptr;
|
||||
|
||||
if (connector->override_edid && edid)
|
||||
seq_write(m, edid->data, edid->length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int edid_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct drm_connector *dev = inode->i_private;
|
||||
|
||||
return single_open(file, edid_show, dev);
|
||||
}
|
||||
|
||||
static ssize_t edid_write(struct file *file, const char __user *ubuf,
|
||||
size_t len, loff_t *offp)
|
||||
{
|
||||
struct seq_file *m = file->private_data;
|
||||
struct drm_connector *connector = m->private;
|
||||
char *buf;
|
||||
struct edid *edid;
|
||||
int ret;
|
||||
|
||||
buf = memdup_user(ubuf, len);
|
||||
if (IS_ERR(buf))
|
||||
return PTR_ERR(buf);
|
||||
|
||||
edid = (struct edid *) buf;
|
||||
|
||||
if (len == 5 && !strncmp(buf, "reset", 5)) {
|
||||
connector->override_edid = false;
|
||||
ret = drm_mode_connector_update_edid_property(connector, NULL);
|
||||
} else if (len < EDID_LENGTH ||
|
||||
EDID_LENGTH * (1 + edid->extensions) > len)
|
||||
ret = -EINVAL;
|
||||
else {
|
||||
connector->override_edid = false;
|
||||
ret = drm_mode_connector_update_edid_property(connector, edid);
|
||||
if (!ret)
|
||||
connector->override_edid = true;
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return (ret) ? ret : len;
|
||||
}
|
||||
|
||||
static const struct file_operations drm_edid_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = edid_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.write = edid_write
|
||||
};
|
||||
|
||||
|
||||
static const struct file_operations drm_connector_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = connector_open,
|
||||
|
@ -333,6 +395,12 @@ int drm_debugfs_connector_add(struct drm_connector *connector)
|
|||
if (!ent)
|
||||
goto error;
|
||||
|
||||
/* edid */
|
||||
ent = debugfs_create_file("edid_override", S_IRUGO | S_IWUSR, root,
|
||||
connector, &drm_edid_fops);
|
||||
if (!ent)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
|
|
@ -130,7 +130,14 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
|
|||
count = drm_load_edid_firmware(connector);
|
||||
if (count == 0)
|
||||
#endif
|
||||
count = (*connector_funcs->get_modes)(connector);
|
||||
{
|
||||
if (connector->override_edid) {
|
||||
struct edid *edid = (struct edid *) connector->edid_blob_ptr->data;
|
||||
|
||||
count = drm_add_edid_modes(connector, edid);
|
||||
} else
|
||||
count = (*connector_funcs->get_modes)(connector);
|
||||
}
|
||||
|
||||
if (count == 0 && connector->status == connector_status_connected)
|
||||
count = drm_add_modes_noedid(connector, 1024, 768);
|
||||
|
|
|
@ -533,6 +533,7 @@ struct drm_connector {
|
|||
|
||||
/* forced on connector */
|
||||
enum drm_connector_force force;
|
||||
bool override_edid;
|
||||
uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
|
||||
struct drm_encoder *encoder; /* currently active encoder */
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче