Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Thomas Wood and committed by
Daniel Vetter
4cf2b281 30f65707

+81 -1
+4
drivers/gpu/drm/drm_crtc.c
··· 3763 3763 struct drm_device *dev = connector->dev; 3764 3764 int ret, size; 3765 3765 3766 + /* ignore requests to set edid when overridden */ 3767 + if (connector->override_edid) 3768 + return 0; 3769 + 3766 3770 if (connector->edid_blob_ptr) 3767 3771 drm_property_destroy_blob(dev, connector->edid_blob_ptr); 3768 3772
+68
drivers/gpu/drm/drm_debugfs.c
··· 35 35 #include <linux/slab.h> 36 36 #include <linux/export.h> 37 37 #include <drm/drmP.h> 38 + #include <drm/drm_edid.h> 38 39 39 40 #if defined(CONFIG_DEBUG_FS) 40 41 ··· 305 304 return len; 306 305 } 307 306 307 + static int edid_show(struct seq_file *m, void *data) 308 + { 309 + struct drm_connector *connector = m->private; 310 + struct drm_property_blob *edid = connector->edid_blob_ptr; 311 + 312 + if (connector->override_edid && edid) 313 + seq_write(m, edid->data, edid->length); 314 + 315 + return 0; 316 + } 317 + 318 + static int edid_open(struct inode *inode, struct file *file) 319 + { 320 + struct drm_connector *dev = inode->i_private; 321 + 322 + return single_open(file, edid_show, dev); 323 + } 324 + 325 + static ssize_t edid_write(struct file *file, const char __user *ubuf, 326 + size_t len, loff_t *offp) 327 + { 328 + struct seq_file *m = file->private_data; 329 + struct drm_connector *connector = m->private; 330 + char *buf; 331 + struct edid *edid; 332 + int ret; 333 + 334 + buf = memdup_user(ubuf, len); 335 + if (IS_ERR(buf)) 336 + return PTR_ERR(buf); 337 + 338 + edid = (struct edid *) buf; 339 + 340 + if (len == 5 && !strncmp(buf, "reset", 5)) { 341 + connector->override_edid = false; 342 + ret = drm_mode_connector_update_edid_property(connector, NULL); 343 + } else if (len < EDID_LENGTH || 344 + EDID_LENGTH * (1 + edid->extensions) > len) 345 + ret = -EINVAL; 346 + else { 347 + connector->override_edid = false; 348 + ret = drm_mode_connector_update_edid_property(connector, edid); 349 + if (!ret) 350 + connector->override_edid = true; 351 + } 352 + 353 + kfree(buf); 354 + 355 + return (ret) ? ret : len; 356 + } 357 + 358 + static const struct file_operations drm_edid_fops = { 359 + .owner = THIS_MODULE, 360 + .open = edid_open, 361 + .read = seq_read, 362 + .llseek = seq_lseek, 363 + .release = single_release, 364 + .write = edid_write 365 + }; 366 + 367 + 308 368 static const struct file_operations drm_connector_fops = { 309 369 .owner = THIS_MODULE, 310 370 .open = connector_open, ··· 392 330 /* force */ 393 331 ent = debugfs_create_file("force", S_IRUGO | S_IWUSR, root, connector, 394 332 &drm_connector_fops); 333 + if (!ent) 334 + goto error; 335 + 336 + /* edid */ 337 + ent = debugfs_create_file("edid_override", S_IRUGO | S_IWUSR, root, 338 + connector, &drm_edid_fops); 395 339 if (!ent) 396 340 goto error; 397 341
+8 -1
drivers/gpu/drm/drm_probe_helper.c
··· 130 130 count = drm_load_edid_firmware(connector); 131 131 if (count == 0) 132 132 #endif 133 - count = (*connector_funcs->get_modes)(connector); 133 + { 134 + if (connector->override_edid) { 135 + struct edid *edid = (struct edid *) connector->edid_blob_ptr->data; 136 + 137 + count = drm_add_edid_modes(connector, edid); 138 + } else 139 + count = (*connector_funcs->get_modes)(connector); 140 + } 134 141 135 142 if (count == 0 && connector->status == connector_status_connected) 136 143 count = drm_add_modes_noedid(connector, 1024, 768);
+1
include/drm/drm_crtc.h
··· 533 533 534 534 /* forced on connector */ 535 535 enum drm_connector_force force; 536 + bool override_edid; 536 537 uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; 537 538 struct drm_encoder *encoder; /* currently active encoder */ 538 539