diff options
author | Thomas Wood <thomas.wood@intel.com> | 2014-06-18 12:52:32 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-06-19 02:56:01 -0400 |
commit | 30f6570798f6c897df4f1f2c676d803728bfec27 (patch) | |
tree | 2ff3e99b8286b75b0cac0a2c07cee9da9c6634bf | |
parent | 34ea3d386347cd6de4c2fa2491dd85c9e753e7e4 (diff) |
drm/debugfs: add a "force" file per connector
Add a file to debugfs for each connector to enable modification of the
"force" connector attribute. This allows connectors to be enabled or
disabled for testing and debugging purposes.
v2: Add stricter value checking and clean up debugfs_entry if file
creation fails in drm_debugfs_connector_add. (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>
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_debugfs.c | 114 | ||||
-rw-r--r-- | include/drm/drmP.h | 11 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 2 |
4 files changed, 143 insertions, 1 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index c50c827cefb6..c304e5650bc8 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -881,6 +881,8 @@ int drm_connector_init(struct drm_device *dev, | |||
881 | drm_object_attach_property(&connector->base, | 881 | drm_object_attach_property(&connector->base, |
882 | dev->mode_config.dpms_property, 0); | 882 | dev->mode_config.dpms_property, 0); |
883 | 883 | ||
884 | connector->debugfs_entry = NULL; | ||
885 | |||
884 | out_put: | 886 | out_put: |
885 | if (ret) | 887 | if (ret) |
886 | drm_mode_object_put(dev, &connector->base); | 888 | drm_mode_object_put(dev, &connector->base); |
@@ -931,7 +933,19 @@ EXPORT_SYMBOL(drm_connector_cleanup); | |||
931 | */ | 933 | */ |
932 | int drm_connector_register(struct drm_connector *connector) | 934 | int drm_connector_register(struct drm_connector *connector) |
933 | { | 935 | { |
934 | return drm_sysfs_connector_add(connector); | 936 | int ret; |
937 | |||
938 | ret = drm_sysfs_connector_add(connector); | ||
939 | if (ret) | ||
940 | return ret; | ||
941 | |||
942 | ret = drm_debugfs_connector_add(connector); | ||
943 | if (ret) { | ||
944 | drm_sysfs_connector_remove(connector); | ||
945 | return ret; | ||
946 | } | ||
947 | |||
948 | return 0; | ||
935 | } | 949 | } |
936 | EXPORT_SYMBOL(drm_connector_register); | 950 | EXPORT_SYMBOL(drm_connector_register); |
937 | 951 | ||
@@ -944,6 +958,7 @@ EXPORT_SYMBOL(drm_connector_register); | |||
944 | void drm_connector_unregister(struct drm_connector *connector) | 958 | void drm_connector_unregister(struct drm_connector *connector) |
945 | { | 959 | { |
946 | drm_sysfs_connector_remove(connector); | 960 | drm_sysfs_connector_remove(connector); |
961 | drm_debugfs_connector_remove(connector); | ||
947 | } | 962 | } |
948 | EXPORT_SYMBOL(drm_connector_unregister); | 963 | EXPORT_SYMBOL(drm_connector_unregister); |
949 | 964 | ||
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index b4b51d46f339..8ab3f3e38643 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c | |||
@@ -237,5 +237,119 @@ int drm_debugfs_cleanup(struct drm_minor *minor) | |||
237 | return 0; | 237 | return 0; |
238 | } | 238 | } |
239 | 239 | ||
240 | static int connector_show(struct seq_file *m, void *data) | ||
241 | { | ||
242 | struct drm_connector *connector = m->private; | ||
243 | const char *status; | ||
244 | |||
245 | switch (connector->force) { | ||
246 | case DRM_FORCE_ON: | ||
247 | status = "on\n"; | ||
248 | break; | ||
249 | |||
250 | case DRM_FORCE_ON_DIGITAL: | ||
251 | status = "digital\n"; | ||
252 | break; | ||
253 | |||
254 | case DRM_FORCE_OFF: | ||
255 | status = "off\n"; | ||
256 | break; | ||
257 | |||
258 | case DRM_FORCE_UNSPECIFIED: | ||
259 | status = "unspecified\n"; | ||
260 | break; | ||
261 | |||
262 | default: | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | seq_puts(m, status); | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int connector_open(struct inode *inode, struct file *file) | ||
272 | { | ||
273 | struct drm_connector *dev = inode->i_private; | ||
274 | |||
275 | return single_open(file, connector_show, dev); | ||
276 | } | ||
277 | |||
278 | static ssize_t connector_write(struct file *file, const char __user *ubuf, | ||
279 | size_t len, loff_t *offp) | ||
280 | { | ||
281 | struct seq_file *m = file->private_data; | ||
282 | struct drm_connector *connector = m->private; | ||
283 | char buf[12]; | ||
284 | |||
285 | if (len > sizeof(buf) - 1) | ||
286 | return -EINVAL; | ||
287 | |||
288 | if (copy_from_user(buf, ubuf, len)) | ||
289 | return -EFAULT; | ||
290 | |||
291 | buf[len] = '\0'; | ||
292 | |||
293 | if (!strcmp(buf, "on")) | ||
294 | connector->force = DRM_FORCE_ON; | ||
295 | else if (!strcmp(buf, "digital")) | ||
296 | connector->force = DRM_FORCE_ON_DIGITAL; | ||
297 | else if (!strcmp(buf, "off")) | ||
298 | connector->force = DRM_FORCE_OFF; | ||
299 | else if (!strcmp(buf, "unspecified")) | ||
300 | connector->force = DRM_FORCE_UNSPECIFIED; | ||
301 | else | ||
302 | return -EINVAL; | ||
303 | |||
304 | return len; | ||
305 | } | ||
306 | |||
307 | static const struct file_operations drm_connector_fops = { | ||
308 | .owner = THIS_MODULE, | ||
309 | .open = connector_open, | ||
310 | .read = seq_read, | ||
311 | .llseek = seq_lseek, | ||
312 | .release = single_release, | ||
313 | .write = connector_write | ||
314 | }; | ||
315 | |||
316 | int drm_debugfs_connector_add(struct drm_connector *connector) | ||
317 | { | ||
318 | struct drm_minor *minor = connector->dev->primary; | ||
319 | struct dentry *root, *ent; | ||
320 | |||
321 | if (!minor->debugfs_root) | ||
322 | return -1; | ||
323 | |||
324 | root = debugfs_create_dir(connector->name, minor->debugfs_root); | ||
325 | if (!root) | ||
326 | return -ENOMEM; | ||
327 | |||
328 | connector->debugfs_entry = root; | ||
329 | |||
330 | /* force */ | ||
331 | ent = debugfs_create_file("force", S_IRUGO | S_IWUSR, root, connector, | ||
332 | &drm_connector_fops); | ||
333 | if (!ent) | ||
334 | goto error; | ||
335 | |||
336 | return 0; | ||
337 | |||
338 | error: | ||
339 | debugfs_remove_recursive(connector->debugfs_entry); | ||
340 | connector->debugfs_entry = NULL; | ||
341 | return -ENOMEM; | ||
342 | } | ||
343 | |||
344 | void drm_debugfs_connector_remove(struct drm_connector *connector) | ||
345 | { | ||
346 | if (!connector->debugfs_entry) | ||
347 | return; | ||
348 | |||
349 | debugfs_remove_recursive(connector->debugfs_entry); | ||
350 | |||
351 | connector->debugfs_entry = NULL; | ||
352 | } | ||
353 | |||
240 | #endif /* CONFIG_DEBUG_FS */ | 354 | #endif /* CONFIG_DEBUG_FS */ |
241 | 355 | ||
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 8af71a8e2c00..57ecc421b19c 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
@@ -1419,6 +1419,8 @@ extern int drm_debugfs_create_files(const struct drm_info_list *files, | |||
1419 | extern int drm_debugfs_remove_files(const struct drm_info_list *files, | 1419 | extern int drm_debugfs_remove_files(const struct drm_info_list *files, |
1420 | int count, struct drm_minor *minor); | 1420 | int count, struct drm_minor *minor); |
1421 | extern int drm_debugfs_cleanup(struct drm_minor *minor); | 1421 | extern int drm_debugfs_cleanup(struct drm_minor *minor); |
1422 | extern int drm_debugfs_connector_add(struct drm_connector *connector); | ||
1423 | extern void drm_debugfs_connector_remove(struct drm_connector *connector); | ||
1422 | #else | 1424 | #else |
1423 | static inline int drm_debugfs_init(struct drm_minor *minor, int minor_id, | 1425 | static inline int drm_debugfs_init(struct drm_minor *minor, int minor_id, |
1424 | struct dentry *root) | 1426 | struct dentry *root) |
@@ -1443,6 +1445,15 @@ static inline int drm_debugfs_cleanup(struct drm_minor *minor) | |||
1443 | { | 1445 | { |
1444 | return 0; | 1446 | return 0; |
1445 | } | 1447 | } |
1448 | |||
1449 | static inline int drm_debugfs_connector_add(struct drm_connector *connector) | ||
1450 | { | ||
1451 | return 0; | ||
1452 | } | ||
1453 | static inline void drm_debugfs_connector_remove(struct drm_connector *connector) | ||
1454 | { | ||
1455 | } | ||
1456 | |||
1446 | #endif | 1457 | #endif |
1447 | 1458 | ||
1448 | /* Info file support */ | 1459 | /* Info file support */ |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 5512c9968d77..d4b0a6a4ad9b 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -545,6 +545,8 @@ struct drm_connector { | |||
545 | int audio_latency[2]; | 545 | int audio_latency[2]; |
546 | int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */ | 546 | int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */ |
547 | unsigned bad_edid_counter; | 547 | unsigned bad_edid_counter; |
548 | |||
549 | struct dentry *debugfs_entry; | ||
548 | }; | 550 | }; |
549 | 551 | ||
550 | /** | 552 | /** |