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