Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 30f65707 authored by Thomas Wood's avatar Thomas Wood Committed by Daniel Vetter
Browse files

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: default avatarThomas Wood <thomas.wood@intel.com>
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 34ea3d38
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -881,6 +881,8 @@ int drm_connector_init(struct drm_device *dev,
	drm_object_attach_property(&connector->base,
				      dev->mode_config.dpms_property, 0);

	connector->debugfs_entry = NULL;

out_put:
	if (ret)
		drm_mode_object_put(dev, &connector->base);
@@ -931,7 +933,19 @@ EXPORT_SYMBOL(drm_connector_cleanup);
 */
int drm_connector_register(struct drm_connector *connector)
{
	return drm_sysfs_connector_add(connector);
	int ret;

	ret = drm_sysfs_connector_add(connector);
	if (ret)
		return ret;

	ret = drm_debugfs_connector_add(connector);
	if (ret) {
		drm_sysfs_connector_remove(connector);
		return ret;
	}

	return 0;
}
EXPORT_SYMBOL(drm_connector_register);

@@ -944,6 +958,7 @@ EXPORT_SYMBOL(drm_connector_register);
void drm_connector_unregister(struct drm_connector *connector)
{
	drm_sysfs_connector_remove(connector);
	drm_debugfs_connector_remove(connector);
}
EXPORT_SYMBOL(drm_connector_unregister);

+114 −0
Original line number Diff line number Diff line
@@ -237,5 +237,119 @@ int drm_debugfs_cleanup(struct drm_minor *minor)
	return 0;
}

static int connector_show(struct seq_file *m, void *data)
{
	struct drm_connector *connector = m->private;
	const char *status;

	switch (connector->force) {
	case DRM_FORCE_ON:
		status = "on\n";
		break;

	case DRM_FORCE_ON_DIGITAL:
		status = "digital\n";
		break;

	case DRM_FORCE_OFF:
		status = "off\n";
		break;

	case DRM_FORCE_UNSPECIFIED:
		status = "unspecified\n";
		break;

	default:
		return 0;
	}

	seq_puts(m, status);

	return 0;
}

static int connector_open(struct inode *inode, struct file *file)
{
	struct drm_connector *dev = inode->i_private;

	return single_open(file, connector_show, dev);
}

static ssize_t connector_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[12];

	if (len > sizeof(buf) - 1)
		return -EINVAL;

	if (copy_from_user(buf, ubuf, len))
		return -EFAULT;

	buf[len] = '\0';

	if (!strcmp(buf, "on"))
		connector->force = DRM_FORCE_ON;
	else if (!strcmp(buf, "digital"))
		connector->force = DRM_FORCE_ON_DIGITAL;
	else if (!strcmp(buf, "off"))
		connector->force = DRM_FORCE_OFF;
	else if (!strcmp(buf, "unspecified"))
		connector->force = DRM_FORCE_UNSPECIFIED;
	else
		return -EINVAL;

	return len;
}

static const struct file_operations drm_connector_fops = {
	.owner = THIS_MODULE,
	.open = connector_open,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
	.write = connector_write
};

int drm_debugfs_connector_add(struct drm_connector *connector)
{
	struct drm_minor *minor = connector->dev->primary;
	struct dentry *root, *ent;

	if (!minor->debugfs_root)
		return -1;

	root = debugfs_create_dir(connector->name, minor->debugfs_root);
	if (!root)
		return -ENOMEM;

	connector->debugfs_entry = root;

	/* force */
	ent = debugfs_create_file("force", S_IRUGO | S_IWUSR, root, connector,
				  &drm_connector_fops);
	if (!ent)
		goto error;

	return 0;

error:
	debugfs_remove_recursive(connector->debugfs_entry);
	connector->debugfs_entry = NULL;
	return -ENOMEM;
}

void drm_debugfs_connector_remove(struct drm_connector *connector)
{
	if (!connector->debugfs_entry)
		return;

	debugfs_remove_recursive(connector->debugfs_entry);

	connector->debugfs_entry = NULL;
}

#endif /* CONFIG_DEBUG_FS */
+11 −0
Original line number Diff line number Diff line
@@ -1419,6 +1419,8 @@ extern int drm_debugfs_create_files(const struct drm_info_list *files,
extern int drm_debugfs_remove_files(const struct drm_info_list *files,
				    int count, struct drm_minor *minor);
extern int drm_debugfs_cleanup(struct drm_minor *minor);
extern int drm_debugfs_connector_add(struct drm_connector *connector);
extern void drm_debugfs_connector_remove(struct drm_connector *connector);
#else
static inline int drm_debugfs_init(struct drm_minor *minor, int minor_id,
				   struct dentry *root)
@@ -1443,6 +1445,15 @@ static inline int drm_debugfs_cleanup(struct drm_minor *minor)
{
	return 0;
}

static inline int drm_debugfs_connector_add(struct drm_connector *connector)
{
	return 0;
}
static inline void drm_debugfs_connector_remove(struct drm_connector *connector)
{
}

#endif

				/* Info file support */
+2 −0
Original line number Diff line number Diff line
@@ -545,6 +545,8 @@ struct drm_connector {
	int audio_latency[2];
	int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
	unsigned bad_edid_counter;

	struct dentry *debugfs_entry;
};

/**