diff options
author | Thomas Wood <thomas.wood@intel.com> | 2014-06-18 12:52:33 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-06-19 02:56:28 -0400 |
commit | 4cf2b28146713d39f78bd62002a8ab00075c63b7 (patch) | |
tree | 15ca4887226be1bd45cd3334a4d0d2d383e855bb /drivers/gpu/drm/drm_debugfs.c | |
parent | 30f6570798f6c897df4f1f2c676d803728bfec27 (diff) |
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>
Diffstat (limited to 'drivers/gpu/drm/drm_debugfs.c')
-rw-r--r-- | drivers/gpu/drm/drm_debugfs.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 8ab3f3e38643..13bd42923dd4 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/export.h> | 36 | #include <linux/export.h> |
37 | #include <drm/drmP.h> | 37 | #include <drm/drmP.h> |
38 | #include <drm/drm_edid.h> | ||
38 | 39 | ||
39 | #if defined(CONFIG_DEBUG_FS) | 40 | #if defined(CONFIG_DEBUG_FS) |
40 | 41 | ||
@@ -304,6 +305,67 @@ static ssize_t connector_write(struct file *file, const char __user *ubuf, | |||
304 | return len; | 305 | return len; |
305 | } | 306 | } |
306 | 307 | ||
308 | static int edid_show(struct seq_file *m, void *data) | ||
309 | { | ||
310 | struct drm_connector *connector = m->private; | ||
311 | struct drm_property_blob *edid = connector->edid_blob_ptr; | ||
312 | |||
313 | if (connector->override_edid && edid) | ||
314 | seq_write(m, edid->data, edid->length); | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int edid_open(struct inode *inode, struct file *file) | ||
320 | { | ||
321 | struct drm_connector *dev = inode->i_private; | ||
322 | |||
323 | return single_open(file, edid_show, dev); | ||
324 | } | ||
325 | |||
326 | static ssize_t edid_write(struct file *file, const char __user *ubuf, | ||
327 | size_t len, loff_t *offp) | ||
328 | { | ||
329 | struct seq_file *m = file->private_data; | ||
330 | struct drm_connector *connector = m->private; | ||
331 | char *buf; | ||
332 | struct edid *edid; | ||
333 | int ret; | ||
334 | |||
335 | buf = memdup_user(ubuf, len); | ||
336 | if (IS_ERR(buf)) | ||
337 | return PTR_ERR(buf); | ||
338 | |||
339 | edid = (struct edid *) buf; | ||
340 | |||
341 | if (len == 5 && !strncmp(buf, "reset", 5)) { | ||
342 | connector->override_edid = false; | ||
343 | ret = drm_mode_connector_update_edid_property(connector, NULL); | ||
344 | } else if (len < EDID_LENGTH || | ||
345 | EDID_LENGTH * (1 + edid->extensions) > len) | ||
346 | ret = -EINVAL; | ||
347 | else { | ||
348 | connector->override_edid = false; | ||
349 | ret = drm_mode_connector_update_edid_property(connector, edid); | ||
350 | if (!ret) | ||
351 | connector->override_edid = true; | ||
352 | } | ||
353 | |||
354 | kfree(buf); | ||
355 | |||
356 | return (ret) ? ret : len; | ||
357 | } | ||
358 | |||
359 | static const struct file_operations drm_edid_fops = { | ||
360 | .owner = THIS_MODULE, | ||
361 | .open = edid_open, | ||
362 | .read = seq_read, | ||
363 | .llseek = seq_lseek, | ||
364 | .release = single_release, | ||
365 | .write = edid_write | ||
366 | }; | ||
367 | |||
368 | |||
307 | static const struct file_operations drm_connector_fops = { | 369 | static const struct file_operations drm_connector_fops = { |
308 | .owner = THIS_MODULE, | 370 | .owner = THIS_MODULE, |
309 | .open = connector_open, | 371 | .open = connector_open, |
@@ -333,6 +395,12 @@ int drm_debugfs_connector_add(struct drm_connector *connector) | |||
333 | if (!ent) | 395 | if (!ent) |
334 | goto error; | 396 | goto error; |
335 | 397 | ||
398 | /* edid */ | ||
399 | ent = debugfs_create_file("edid_override", S_IRUGO | S_IWUSR, root, | ||
400 | connector, &drm_edid_fops); | ||
401 | if (!ent) | ||
402 | goto error; | ||
403 | |||
336 | return 0; | 404 | return 0; |
337 | 405 | ||
338 | error: | 406 | error: |