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/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 :
50 : static struct device_type drm_sysfs_device_minor = {
51 : .name = "drm_minor"
52 : };
53 :
54 : static struct device_type drm_sysfs_device_connector = {
55 : .name = "drm_connector",
56 : };
57 :
58 : struct class *drm_class;
59 :
60 : #ifdef CONFIG_ACPI
61 : static bool drm_connector_acpi_bus_match(struct device *dev)
62 : {
63 : return dev->type == &drm_sysfs_device_connector;
64 : }
65 :
66 : static 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 :
73 : static 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 :
79 : static void drm_sysfs_acpi_register(void)
80 : {
81 : register_acpi_bus_type(&drm_connector_acpi_bus);
82 : }
83 :
84 : static void drm_sysfs_acpi_unregister(void)
85 : {
86 : unregister_acpi_bus_type(&drm_connector_acpi_bus);
87 : }
88 : #else
89 : static void drm_sysfs_acpi_register(void) { }
90 : static void drm_sysfs_acpi_unregister(void) { }
91 : #endif
92 :
93 0 : static char *drm_devnode(struct device *dev, umode_t *mode)
94 : {
95 0 : return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
96 : }
97 :
98 : static 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 : */
110 1 : int drm_sysfs_init(void)
111 : {
112 : int err;
113 :
114 1 : drm_class = class_create(THIS_MODULE, "drm");
115 2 : if (IS_ERR(drm_class))
116 0 : return PTR_ERR(drm_class);
117 :
118 2 : err = class_create_file(drm_class, &class_attr_version.attr);
119 1 : if (err) {
120 0 : class_destroy(drm_class);
121 0 : drm_class = NULL;
122 0 : return err;
123 : }
124 :
125 1 : drm_class->devnode = drm_devnode;
126 :
127 : drm_sysfs_acpi_register();
128 1 : return 0;
129 : }
130 :
131 : /**
132 : * drm_sysfs_destroy - destroys DRM class
133 : *
134 : * Destroy the DRM device class.
135 : */
136 0 : void drm_sysfs_destroy(void)
137 : {
138 0 : if (IS_ERR_OR_NULL(drm_class))
139 : return;
140 : drm_sysfs_acpi_unregister();
141 0 : class_remove_file(drm_class, &class_attr_version.attr);
142 0 : class_destroy(drm_class);
143 0 : drm_class = NULL;
144 : }
145 :
146 0 : static void drm_sysfs_release(struct device *dev)
147 : {
148 0 : kfree(dev);
149 0 : }
150 :
151 : /*
152 : * Connector properties
153 : */
154 0 : static ssize_t status_store(struct device *device,
155 : struct device_attribute *attr,
156 : const char *buf, size_t count)
157 : {
158 0 : struct drm_connector *connector = to_drm_connector(device);
159 0 : struct drm_device *dev = connector->dev;
160 : enum drm_connector_force old_force;
161 : int ret;
162 :
163 0 : ret = mutex_lock_interruptible(&dev->mode_config.mutex);
164 0 : if (ret)
165 0 : return ret;
166 :
167 0 : old_force = connector->force;
168 :
169 0 : if (sysfs_streq(buf, "detect"))
170 0 : connector->force = 0;
171 0 : else if (sysfs_streq(buf, "on"))
172 0 : connector->force = DRM_FORCE_ON;
173 0 : else if (sysfs_streq(buf, "on-digital"))
174 0 : connector->force = DRM_FORCE_ON_DIGITAL;
175 0 : else if (sysfs_streq(buf, "off"))
176 0 : connector->force = DRM_FORCE_OFF;
177 : else
178 : ret = -EINVAL;
179 :
180 0 : if (old_force != connector->force || !connector->force) {
181 0 : 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 0 : connector->funcs->fill_modes(connector,
187 0 : dev->mode_config.max_width,
188 0 : dev->mode_config.max_height);
189 : }
190 :
191 0 : mutex_unlock(&dev->mode_config.mutex);
192 :
193 0 : return ret ? ret : count;
194 : }
195 :
196 0 : static ssize_t status_show(struct device *device,
197 : struct device_attribute *attr,
198 : char *buf)
199 : {
200 0 : struct drm_connector *connector = to_drm_connector(device);
201 : enum drm_connector_status status;
202 :
203 0 : status = READ_ONCE(connector->status);
204 :
205 0 : return sysfs_emit(buf, "%s\n",
206 : drm_get_connector_status_name(status));
207 : }
208 :
209 0 : static ssize_t dpms_show(struct device *device,
210 : struct device_attribute *attr,
211 : char *buf)
212 : {
213 0 : struct drm_connector *connector = to_drm_connector(device);
214 : int dpms;
215 :
216 0 : dpms = READ_ONCE(connector->dpms);
217 :
218 0 : return sysfs_emit(buf, "%s\n", drm_get_dpms_name(dpms));
219 : }
220 :
221 0 : static ssize_t enabled_show(struct device *device,
222 : struct device_attribute *attr,
223 : char *buf)
224 : {
225 0 : struct drm_connector *connector = to_drm_connector(device);
226 : bool enabled;
227 :
228 0 : enabled = READ_ONCE(connector->encoder);
229 :
230 0 : return sysfs_emit(buf, enabled ? "enabled\n" : "disabled\n");
231 : }
232 :
233 0 : static ssize_t edid_show(struct file *filp, struct kobject *kobj,
234 : struct bin_attribute *attr, char *buf, loff_t off,
235 : size_t count)
236 : {
237 0 : struct device *connector_dev = kobj_to_dev(kobj);
238 0 : struct drm_connector *connector = to_drm_connector(connector_dev);
239 : unsigned char *edid;
240 : size_t size;
241 0 : ssize_t ret = 0;
242 :
243 0 : mutex_lock(&connector->dev->mode_config.mutex);
244 0 : if (!connector->edid_blob_ptr)
245 : goto unlock;
246 :
247 0 : edid = connector->edid_blob_ptr->data;
248 0 : size = connector->edid_blob_ptr->length;
249 0 : if (!edid)
250 : goto unlock;
251 :
252 0 : if (off >= size)
253 : goto unlock;
254 :
255 0 : if (off + count > size)
256 0 : count = size - off;
257 0 : memcpy(buf, edid + off, count);
258 :
259 0 : ret = count;
260 : unlock:
261 0 : mutex_unlock(&connector->dev->mode_config.mutex);
262 :
263 0 : return ret;
264 : }
265 :
266 0 : static ssize_t modes_show(struct device *device,
267 : struct device_attribute *attr,
268 : char *buf)
269 : {
270 0 : struct drm_connector *connector = to_drm_connector(device);
271 : struct drm_display_mode *mode;
272 0 : int written = 0;
273 :
274 0 : mutex_lock(&connector->dev->mode_config.mutex);
275 0 : list_for_each_entry(mode, &connector->modes, head) {
276 0 : written += scnprintf(buf + written, PAGE_SIZE - written, "%s\n",
277 0 : mode->name);
278 : }
279 0 : mutex_unlock(&connector->dev->mode_config.mutex);
280 :
281 0 : return written;
282 : }
283 :
284 : static DEVICE_ATTR_RW(status);
285 : static DEVICE_ATTR_RO(enabled);
286 : static DEVICE_ATTR_RO(dpms);
287 : static DEVICE_ATTR_RO(modes);
288 :
289 : static struct attribute *connector_dev_attrs[] = {
290 : &dev_attr_status.attr,
291 : &dev_attr_enabled.attr,
292 : &dev_attr_dpms.attr,
293 : &dev_attr_modes.attr,
294 : NULL
295 : };
296 :
297 : static struct bin_attribute edid_attr = {
298 : .attr.name = "edid",
299 : .attr.mode = 0444,
300 : .size = 0,
301 : .read = edid_show,
302 : };
303 :
304 : static struct bin_attribute *connector_bin_attrs[] = {
305 : &edid_attr,
306 : NULL
307 : };
308 :
309 : static const struct attribute_group connector_dev_group = {
310 : .attrs = connector_dev_attrs,
311 : .bin_attrs = connector_bin_attrs,
312 : };
313 :
314 : static const struct attribute_group *connector_dev_groups[] = {
315 : &connector_dev_group,
316 : NULL
317 : };
318 :
319 0 : int drm_sysfs_connector_add(struct drm_connector *connector)
320 : {
321 0 : struct drm_device *dev = connector->dev;
322 : struct device *kdev;
323 : int r;
324 :
325 0 : if (connector->kdev)
326 : return 0;
327 :
328 0 : kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
329 0 : if (!kdev)
330 : return -ENOMEM;
331 :
332 0 : device_initialize(kdev);
333 0 : kdev->class = drm_class;
334 0 : kdev->type = &drm_sysfs_device_connector;
335 0 : kdev->parent = dev->primary->kdev;
336 0 : kdev->groups = connector_dev_groups;
337 0 : kdev->release = drm_sysfs_release;
338 0 : dev_set_drvdata(kdev, connector);
339 :
340 0 : r = dev_set_name(kdev, "card%d-%s", dev->primary->index, connector->name);
341 0 : if (r)
342 : goto err_free;
343 :
344 0 : DRM_DEBUG("adding \"%s\" to sysfs\n",
345 : connector->name);
346 :
347 0 : r = device_add(kdev);
348 0 : if (r) {
349 0 : drm_err(dev, "failed to register connector device: %d\n", r);
350 0 : goto err_free;
351 : }
352 :
353 0 : connector->kdev = kdev;
354 :
355 0 : if (connector->ddc)
356 0 : return sysfs_create_link(&connector->kdev->kobj,
357 : &connector->ddc->dev.kobj, "ddc");
358 : return 0;
359 :
360 : err_free:
361 0 : put_device(kdev);
362 0 : return r;
363 : }
364 :
365 0 : void drm_sysfs_connector_remove(struct drm_connector *connector)
366 : {
367 0 : if (!connector->kdev)
368 : return;
369 :
370 0 : if (connector->ddc)
371 0 : sysfs_remove_link(&connector->kdev->kobj, "ddc");
372 :
373 0 : DRM_DEBUG("removing \"%s\" from sysfs\n",
374 : connector->name);
375 :
376 0 : device_unregister(connector->kdev);
377 0 : connector->kdev = NULL;
378 : }
379 :
380 0 : void drm_sysfs_lease_event(struct drm_device *dev)
381 : {
382 0 : char *event_string = "LEASE=1";
383 0 : char *envp[] = { event_string, NULL };
384 :
385 0 : DRM_DEBUG("generating lease event\n");
386 :
387 0 : kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
388 0 : }
389 :
390 : /**
391 : * drm_sysfs_hotplug_event - generate a DRM uevent
392 : * @dev: DRM device
393 : *
394 : * Send a uevent for the DRM device specified by @dev. Currently we only
395 : * set HOTPLUG=1 in the uevent environment, but this could be expanded to
396 : * deal with other types of events.
397 : *
398 : * Any new uapi should be using the drm_sysfs_connector_status_event()
399 : * for uevents on connector status change.
400 : */
401 0 : void drm_sysfs_hotplug_event(struct drm_device *dev)
402 : {
403 0 : char *event_string = "HOTPLUG=1";
404 0 : char *envp[] = { event_string, NULL };
405 :
406 0 : DRM_DEBUG("generating hotplug event\n");
407 :
408 0 : kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
409 0 : }
410 : EXPORT_SYMBOL(drm_sysfs_hotplug_event);
411 :
412 : /**
413 : * drm_sysfs_connector_hotplug_event - generate a DRM uevent for any connector
414 : * change
415 : * @connector: connector which has changed
416 : *
417 : * Send a uevent for the DRM connector specified by @connector. This will send
418 : * a uevent with the properties HOTPLUG=1 and CONNECTOR.
419 : */
420 0 : void drm_sysfs_connector_hotplug_event(struct drm_connector *connector)
421 : {
422 0 : struct drm_device *dev = connector->dev;
423 0 : char hotplug_str[] = "HOTPLUG=1", conn_id[21];
424 0 : char *envp[] = { hotplug_str, conn_id, NULL };
425 :
426 0 : snprintf(conn_id, sizeof(conn_id),
427 : "CONNECTOR=%u", connector->base.id);
428 :
429 0 : drm_dbg_kms(connector->dev,
430 : "[CONNECTOR:%d:%s] generating connector hotplug event\n",
431 : connector->base.id, connector->name);
432 :
433 0 : kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
434 0 : }
435 : EXPORT_SYMBOL(drm_sysfs_connector_hotplug_event);
436 :
437 : /**
438 : * drm_sysfs_connector_status_event - generate a DRM uevent for connector
439 : * property status change
440 : * @connector: connector on which property status changed
441 : * @property: connector property whose status changed.
442 : *
443 : * Send a uevent for the DRM device specified by @dev. Currently we
444 : * set HOTPLUG=1 and connector id along with the attached property id
445 : * related to the status change.
446 : */
447 0 : void drm_sysfs_connector_status_event(struct drm_connector *connector,
448 : struct drm_property *property)
449 : {
450 0 : struct drm_device *dev = connector->dev;
451 0 : char hotplug_str[] = "HOTPLUG=1", conn_id[21], prop_id[21];
452 0 : char *envp[4] = { hotplug_str, conn_id, prop_id, NULL };
453 :
454 0 : WARN_ON(!drm_mode_obj_find_prop_id(&connector->base,
455 : property->base.id));
456 :
457 0 : snprintf(conn_id, ARRAY_SIZE(conn_id),
458 : "CONNECTOR=%u", connector->base.id);
459 0 : snprintf(prop_id, ARRAY_SIZE(prop_id),
460 : "PROPERTY=%u", property->base.id);
461 :
462 0 : DRM_DEBUG("generating connector status event\n");
463 :
464 0 : kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
465 0 : }
466 : EXPORT_SYMBOL(drm_sysfs_connector_status_event);
467 :
468 0 : struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
469 : {
470 : const char *minor_str;
471 : struct device *kdev;
472 : int r;
473 :
474 0 : if (minor->type == DRM_MINOR_RENDER)
475 : minor_str = "renderD%d";
476 : else
477 0 : minor_str = "card%d";
478 :
479 0 : kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
480 0 : if (!kdev)
481 : return ERR_PTR(-ENOMEM);
482 :
483 0 : device_initialize(kdev);
484 0 : kdev->devt = MKDEV(DRM_MAJOR, minor->index);
485 0 : kdev->class = drm_class;
486 0 : kdev->type = &drm_sysfs_device_minor;
487 0 : kdev->parent = minor->dev->dev;
488 0 : kdev->release = drm_sysfs_release;
489 0 : dev_set_drvdata(kdev, minor);
490 :
491 0 : r = dev_set_name(kdev, minor_str, minor->index);
492 0 : if (r < 0)
493 : goto err_free;
494 :
495 : return kdev;
496 :
497 : err_free:
498 0 : put_device(kdev);
499 0 : return ERR_PTR(r);
500 : }
501 :
502 : /**
503 : * drm_class_device_register - register new device with the DRM sysfs class
504 : * @dev: device to register
505 : *
506 : * Registers a new &struct device within the DRM sysfs class. Essentially only
507 : * used by ttm to have a place for its global settings. Drivers should never use
508 : * this.
509 : */
510 0 : int drm_class_device_register(struct device *dev)
511 : {
512 0 : if (!drm_class || IS_ERR(drm_class))
513 : return -ENOENT;
514 :
515 0 : dev->class = drm_class;
516 0 : return device_register(dev);
517 : }
518 : EXPORT_SYMBOL_GPL(drm_class_device_register);
519 :
520 : /**
521 : * drm_class_device_unregister - unregister device with the DRM sysfs class
522 : * @dev: device to unregister
523 : *
524 : * Unregisters a &struct device from the DRM sysfs class. Essentially only used
525 : * by ttm to have a place for its global settings. Drivers should never use
526 : * this.
527 : */
528 0 : void drm_class_device_unregister(struct device *dev)
529 : {
530 0 : return device_unregister(dev);
531 : }
532 : EXPORT_SYMBOL_GPL(drm_class_device_unregister);
|