1// SPDX-License-Identifier: GPL-2.0-only
2
3/*
4 * drm_sysfs.c - Modifications to drm_sysfs_class.c to support
5 *               extra sysfs attribute from DRM. Normal drm_sysfs_class
6 *               does not allow adding attributes.
7 *
8 * Copyright (c) 2004 Jon Smirl <jonsmirl@gmail.com>
9 * Copyright (c) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
10 * Copyright (c) 2003-2004 IBM Corp.
11 */
12
13#include <linux/acpi.h>
14#include <linux/device.h>
15#include <linux/err.h>
16#include <linux/export.h>
17#include <linux/gfp.h>
18#include <linux/i2c.h>
19#include <linux/kdev_t.h>
20#include <linux/slab.h>
21
22#include <drm/drm_connector.h>
23#include <drm/drm_device.h>
24#include <drm/drm_file.h>
25#include <drm/drm_modes.h>
26#include <drm/drm_print.h>
27#include <drm/drm_property.h>
28#include <drm/drm_sysfs.h>
29
30#include "drm_internal.h"
31#include "drm_crtc_internal.h"
32
33#define to_drm_minor(d) dev_get_drvdata(d)
34#define to_drm_connector(d) dev_get_drvdata(d)
35
36/**
37 * DOC: overview
38 *
39 * DRM provides very little additional support to drivers for sysfs
40 * interactions, beyond just all the standard stuff. Drivers who want to expose
41 * additional sysfs properties and property groups can attach them at either
42 * &drm_device.dev or &drm_connector.kdev.
43 *
44 * Registration is automatically handled when calling drm_dev_register(), or
45 * drm_connector_register() in case of hot-plugged connectors. Unregistration is
46 * also automatically handled by drm_dev_unregister() and
47 * drm_connector_unregister().
48 */
49
50static struct device_type drm_sysfs_device_minor = {
51	.name = "drm_minor"
52};
53
54static struct device_type drm_sysfs_device_connector = {
55	.name = "drm_connector",
56};
57
58struct class *drm_class;
59
60#ifdef CONFIG_ACPI
61static bool drm_connector_acpi_bus_match(struct device *dev)
62{
63	return dev->type == &drm_sysfs_device_connector;
64}
65
66static struct acpi_device *drm_connector_acpi_find_companion(struct device *dev)
67{
68	struct drm_connector *connector = to_drm_connector(dev);
69
70	return to_acpi_device_node(connector->fwnode);
71}
72
73static struct acpi_bus_type drm_connector_acpi_bus = {
74	.name = "drm_connector",
75	.match = drm_connector_acpi_bus_match,
76	.find_companion = drm_connector_acpi_find_companion,
77};
78
79static void drm_sysfs_acpi_register(void)
80{
81	register_acpi_bus_type(&drm_connector_acpi_bus);
82}
83
84static void drm_sysfs_acpi_unregister(void)
85{
86	unregister_acpi_bus_type(&drm_connector_acpi_bus);
87}
88#else
89static void drm_sysfs_acpi_register(void) { }
90static void drm_sysfs_acpi_unregister(void) { }
91#endif
92
93static char *drm_devnode(struct device *dev, umode_t *mode)
94{
95	return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
96}
97
98static CLASS_ATTR_STRING(version, S_IRUGO, "drm 1.1.0 20060810");
99
100/**
101 * drm_sysfs_init - initialize sysfs helpers
102 *
103 * This is used to create the DRM class, which is the implicit parent of any
104 * other top-level DRM sysfs objects.
105 *
106 * You must call drm_sysfs_destroy() to release the allocated resources.
107 *
108 * Return: 0 on success, negative error code on failure.
109 */
110int drm_sysfs_init(void)
111{
112	int err;
113
114	drm_class = class_create(THIS_MODULE, "drm");
115	if (IS_ERR(drm_class))
116		return PTR_ERR(drm_class);
117
118	err = class_create_file(drm_class, &class_attr_version.attr);
119	if (err) {
120		class_destroy(drm_class);
121		drm_class = NULL;
122		return err;
123	}
124
125	drm_class->devnode = drm_devnode;
126
127	drm_sysfs_acpi_register();
128	return 0;
129}
130
131/**
132 * drm_sysfs_destroy - destroys DRM class
133 *
134 * Destroy the DRM device class.
135 */
136void drm_sysfs_destroy(void)
137{
138	if (IS_ERR_OR_NULL(drm_class))
139		return;
140	drm_sysfs_acpi_unregister();
141	class_remove_file(drm_class, &class_attr_version.attr);
142	class_destroy(drm_class);
143	drm_class = NULL;
144}
145
146static void drm_sysfs_release(struct device *dev)
147{
148	kfree(dev);
149}
150
151/*
152 * Connector properties
153 */
154static ssize_t status_store(struct device *device,
155			   struct device_attribute *attr,
156			   const char *buf, size_t count)
157{
158	struct drm_connector *connector = to_drm_connector(device);
159	struct drm_device *dev = connector->dev;
160	enum drm_connector_force old_force;
161	int ret;
162
163	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
164	if (ret)
165		return ret;
166
167	old_force = connector->force;
168
169	if (sysfs_streq(buf, "detect"))
170		connector->force = 0;
171	else if (sysfs_streq(buf, "on"))
172		connector->force = DRM_FORCE_ON;
173	else if (sysfs_streq(buf, "on-digital"))
174		connector->force = DRM_FORCE_ON_DIGITAL;
175	else if (sysfs_streq(buf, "off"))
176		connector->force = DRM_FORCE_OFF;
177	else
178		ret = -EINVAL;
179
180	if (old_force != connector->force || !connector->force) {
181		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force updated from %d to %d or reprobing\n",
182			      connector->base.id,
183			      connector->name,
184			      old_force, connector->force);
185
186		connector->funcs->fill_modes(connector,
187					     dev->mode_config.max_width,
188					     dev->mode_config.max_height);
189	}
190
191	mutex_unlock(&dev->mode_config.mutex);
192
193	return ret ? ret : count;
194}
195
196static ssize_t status_show(struct device *device,
197			   struct device_attribute *attr,
198			   char *buf)
199{
200	struct drm_connector *connector = to_drm_connector(device);
201	enum drm_connector_status status;
202
203	status = READ_ONCE(connector->status);
204
205	return snprintf(buf, PAGE_SIZE, "%s\n",
206			drm_get_connector_status_name(status));
207}
208
209static ssize_t dpms_show(struct device *device,
210			   struct device_attribute *attr,
211			   char *buf)
212{
213	struct drm_connector *connector = to_drm_connector(device);
214	int dpms;
215
216	dpms = READ_ONCE(connector->dpms);
217
218	return snprintf(buf, PAGE_SIZE, "%s\n",
219			drm_get_dpms_name(dpms));
220}
221
222static ssize_t enabled_show(struct device *device,
223			    struct device_attribute *attr,
224			   char *buf)
225{
226	struct drm_connector *connector = to_drm_connector(device);
227	bool enabled;
228
229	enabled = READ_ONCE(connector->encoder);
230
231	return snprintf(buf, PAGE_SIZE, enabled ? "enabled\n" : "disabled\n");
232}
233
234static ssize_t edid_show(struct file *filp, struct kobject *kobj,
235			 struct bin_attribute *attr, char *buf, loff_t off,
236			 size_t count)
237{
238	struct device *connector_dev = kobj_to_dev(kobj);
239	struct drm_connector *connector = to_drm_connector(connector_dev);
240	unsigned char *edid;
241	size_t size;
242	ssize_t ret = 0;
243
244	mutex_lock(&connector->dev->mode_config.mutex);
245	if (!connector->edid_blob_ptr)
246		goto unlock;
247
248	edid = connector->edid_blob_ptr->data;
249	size = connector->edid_blob_ptr->length;
250	if (!edid)
251		goto unlock;
252
253	if (off >= size)
254		goto unlock;
255
256	if (off + count > size)
257		count = size - off;
258	memcpy(buf, edid + off, count);
259
260	ret = count;
261unlock:
262	mutex_unlock(&connector->dev->mode_config.mutex);
263
264	return ret;
265}
266
267static ssize_t modes_show(struct device *device,
268			   struct device_attribute *attr,
269			   char *buf)
270{
271	struct drm_connector *connector = to_drm_connector(device);
272	struct drm_display_mode *mode;
273	int written = 0;
274
275	mutex_lock(&connector->dev->mode_config.mutex);
276	list_for_each_entry(mode, &connector->modes, head) {
277		written += scnprintf(buf + written, PAGE_SIZE - written, "%s\n",
278				    mode->name);
279	}
280	mutex_unlock(&connector->dev->mode_config.mutex);
281
282	return written;
283}
284
285static DEVICE_ATTR_RW(status);
286static DEVICE_ATTR_RO(enabled);
287static DEVICE_ATTR_RO(dpms);
288static DEVICE_ATTR_RO(modes);
289
290static struct attribute *connector_dev_attrs[] = {
291	&dev_attr_status.attr,
292	&dev_attr_enabled.attr,
293	&dev_attr_dpms.attr,
294	&dev_attr_modes.attr,
295	NULL
296};
297
298static struct bin_attribute edid_attr = {
299	.attr.name = "edid",
300	.attr.mode = 0444,
301	.size = 0,
302	.read = edid_show,
303};
304
305static struct bin_attribute *connector_bin_attrs[] = {
306	&edid_attr,
307	NULL
308};
309
310static const struct attribute_group connector_dev_group = {
311	.attrs = connector_dev_attrs,
312	.bin_attrs = connector_bin_attrs,
313};
314
315static const struct attribute_group *connector_dev_groups[] = {
316	&connector_dev_group,
317	NULL
318};
319
320int drm_sysfs_connector_add(struct drm_connector *connector)
321{
322	struct drm_device *dev = connector->dev;
323	struct device *kdev;
324	int r;
325
326	if (connector->kdev)
327		return 0;
328
329	kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
330	if (!kdev)
331		return -ENOMEM;
332
333	device_initialize(kdev);
334	kdev->class = drm_class;
335	kdev->type = &drm_sysfs_device_connector;
336	kdev->parent = dev->primary->kdev;
337	kdev->groups = connector_dev_groups;
338	kdev->release = drm_sysfs_release;
339	dev_set_drvdata(kdev, connector);
340
341	r = dev_set_name(kdev, "card%d-%s", dev->primary->index, connector->name);
342	if (r)
343		goto err_free;
344
345	DRM_DEBUG("adding \"%s\" to sysfs\n",
346		  connector->name);
347
348	r = device_add(kdev);
349	if (r) {
350		drm_err(dev, "failed to register connector device: %d\n", r);
351		goto err_free;
352	}
353
354	connector->kdev = kdev;
355
356	if (connector->ddc)
357		return sysfs_create_link(&connector->kdev->kobj,
358				 &connector->ddc->dev.kobj, "ddc");
359	return 0;
360
361err_free:
362	put_device(kdev);
363	return r;
364}
365
366void drm_sysfs_connector_remove(struct drm_connector *connector)
367{
368	if (!connector->kdev)
369		return;
370
371	if (connector->ddc)
372		sysfs_remove_link(&connector->kdev->kobj, "ddc");
373
374	DRM_DEBUG("removing \"%s\" from sysfs\n",
375		  connector->name);
376
377	device_unregister(connector->kdev);
378	connector->kdev = NULL;
379}
380
381void drm_sysfs_lease_event(struct drm_device *dev)
382{
383	char *event_string = "LEASE=1";
384	char *envp[] = { event_string, NULL };
385
386	DRM_DEBUG("generating lease event\n");
387
388	kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
389}
390
391/**
392 * drm_sysfs_hotplug_event - generate a DRM uevent
393 * @dev: DRM device
394 *
395 * Send a uevent for the DRM device specified by @dev.  Currently we only
396 * set HOTPLUG=1 in the uevent environment, but this could be expanded to
397 * deal with other types of events.
398 *
399 * Any new uapi should be using the drm_sysfs_connector_status_event()
400 * for uevents on connector status change.
401 */
402void drm_sysfs_hotplug_event(struct drm_device *dev)
403{
404	char *event_string = "HOTPLUG=1";
405	char *envp[] = { event_string, NULL };
406
407	DRM_DEBUG("generating hotplug event\n");
408
409	kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
410}
411EXPORT_SYMBOL(drm_sysfs_hotplug_event);
412
413/**
414 * drm_sysfs_connector_status_event - generate a DRM uevent for connector
415 * property status change
416 * @connector: connector on which property status changed
417 * @property: connector property whose status changed.
418 *
419 * Send a uevent for the DRM device specified by @dev.  Currently we
420 * set HOTPLUG=1 and connector id along with the attached property id
421 * related to the status change.
422 */
423void drm_sysfs_connector_status_event(struct drm_connector *connector,
424				      struct drm_property *property)
425{
426	struct drm_device *dev = connector->dev;
427	char hotplug_str[] = "HOTPLUG=1", conn_id[21], prop_id[21];
428	char *envp[4] = { hotplug_str, conn_id, prop_id, NULL };
429
430	WARN_ON(!drm_mode_obj_find_prop_id(&connector->base,
431					   property->base.id));
432
433	snprintf(conn_id, ARRAY_SIZE(conn_id),
434		 "CONNECTOR=%u", connector->base.id);
435	snprintf(prop_id, ARRAY_SIZE(prop_id),
436		 "PROPERTY=%u", property->base.id);
437
438	DRM_DEBUG("generating connector status event\n");
439
440	kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
441}
442EXPORT_SYMBOL(drm_sysfs_connector_status_event);
443
444struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
445{
446	const char *minor_str;
447	struct device *kdev;
448	int r;
449
450	if (minor->type == DRM_MINOR_RENDER)
451		minor_str = "renderD%d";
452	else
453		minor_str = "card%d";
454
455	kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
456	if (!kdev)
457		return ERR_PTR(-ENOMEM);
458
459	device_initialize(kdev);
460	kdev->devt = MKDEV(DRM_MAJOR, minor->index);
461	kdev->class = drm_class;
462	kdev->type = &drm_sysfs_device_minor;
463	kdev->parent = minor->dev->dev;
464	kdev->release = drm_sysfs_release;
465	dev_set_drvdata(kdev, minor);
466
467	r = dev_set_name(kdev, minor_str, minor->index);
468	if (r < 0)
469		goto err_free;
470
471	return kdev;
472
473err_free:
474	put_device(kdev);
475	return ERR_PTR(r);
476}
477
478/**
479 * drm_class_device_register - register new device with the DRM sysfs class
480 * @dev: device to register
481 *
482 * Registers a new &struct device within the DRM sysfs class. Essentially only
483 * used by ttm to have a place for its global settings. Drivers should never use
484 * this.
485 */
486int drm_class_device_register(struct device *dev)
487{
488	if (!drm_class || IS_ERR(drm_class))
489		return -ENOENT;
490
491	dev->class = drm_class;
492	return device_register(dev);
493}
494EXPORT_SYMBOL_GPL(drm_class_device_register);
495
496/**
497 * drm_class_device_unregister - unregister device with the DRM sysfs class
498 * @dev: device to unregister
499 *
500 * Unregisters a &struct device from the DRM sysfs class. Essentially only used
501 * by ttm to have a place for its global settings. Drivers should never use
502 * this.
503 */
504void drm_class_device_unregister(struct device *dev)
505{
506	return device_unregister(dev);
507}
508EXPORT_SYMBOL_GPL(drm_class_device_unregister);
509