linux/drivers/gpu/drm/drm_sysfs.c
<<
>>
Prefs
   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/device.h>
  14#include <linux/err.h>
  15#include <linux/export.h>
  16#include <linux/gfp.h>
  17#include <linux/kdev_t.h>
  18#include <linux/slab.h>
  19
  20#include <drm/drm_connector.h>
  21#include <drm/drm_device.h>
  22#include <drm/drm_file.h>
  23#include <drm/drm_modes.h>
  24#include <drm/drm_print.h>
  25#include <drm/drm_property.h>
  26#include <drm/drm_sysfs.h>
  27
  28#include "drm_internal.h"
  29
  30#define to_drm_minor(d) dev_get_drvdata(d)
  31#define to_drm_connector(d) dev_get_drvdata(d)
  32
  33/**
  34 * DOC: overview
  35 *
  36 * DRM provides very little additional support to drivers for sysfs
  37 * interactions, beyond just all the standard stuff. Drivers who want to expose
  38 * additional sysfs properties and property groups can attach them at either
  39 * &drm_device.dev or &drm_connector.kdev.
  40 *
  41 * Registration is automatically handled when calling drm_dev_register(), or
  42 * drm_connector_register() in case of hot-plugged connectors. Unregistration is
  43 * also automatically handled by drm_dev_unregister() and
  44 * drm_connector_unregister().
  45 */
  46
  47static struct device_type drm_sysfs_device_minor = {
  48        .name = "drm_minor"
  49};
  50
  51struct class *drm_class;
  52
  53static char *drm_devnode(struct device *dev, umode_t *mode)
  54{
  55        return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
  56}
  57
  58static CLASS_ATTR_STRING(version, S_IRUGO, "drm 1.1.0 20060810");
  59
  60/**
  61 * drm_sysfs_init - initialize sysfs helpers
  62 *
  63 * This is used to create the DRM class, which is the implicit parent of any
  64 * other top-level DRM sysfs objects.
  65 *
  66 * You must call drm_sysfs_destroy() to release the allocated resources.
  67 *
  68 * Return: 0 on success, negative error code on failure.
  69 */
  70int drm_sysfs_init(void)
  71{
  72        int err;
  73
  74        drm_class = class_create(THIS_MODULE, "drm");
  75        if (IS_ERR(drm_class))
  76                return PTR_ERR(drm_class);
  77
  78        err = class_create_file(drm_class, &class_attr_version.attr);
  79        if (err) {
  80                class_destroy(drm_class);
  81                drm_class = NULL;
  82                return err;
  83        }
  84
  85        drm_class->devnode = drm_devnode;
  86        drm_setup_hdcp_srm(drm_class);
  87        return 0;
  88}
  89
  90/**
  91 * drm_sysfs_destroy - destroys DRM class
  92 *
  93 * Destroy the DRM device class.
  94 */
  95void drm_sysfs_destroy(void)
  96{
  97        if (IS_ERR_OR_NULL(drm_class))
  98                return;
  99        drm_teardown_hdcp_srm(drm_class);
 100        class_remove_file(drm_class, &class_attr_version.attr);
 101        class_destroy(drm_class);
 102        drm_class = NULL;
 103}
 104
 105/*
 106 * Connector properties
 107 */
 108static ssize_t status_store(struct device *device,
 109                           struct device_attribute *attr,
 110                           const char *buf, size_t count)
 111{
 112        struct drm_connector *connector = to_drm_connector(device);
 113        struct drm_device *dev = connector->dev;
 114        enum drm_connector_force old_force;
 115        int ret;
 116
 117        ret = mutex_lock_interruptible(&dev->mode_config.mutex);
 118        if (ret)
 119                return ret;
 120
 121        old_force = connector->force;
 122
 123        if (sysfs_streq(buf, "detect"))
 124                connector->force = 0;
 125        else if (sysfs_streq(buf, "on"))
 126                connector->force = DRM_FORCE_ON;
 127        else if (sysfs_streq(buf, "on-digital"))
 128                connector->force = DRM_FORCE_ON_DIGITAL;
 129        else if (sysfs_streq(buf, "off"))
 130                connector->force = DRM_FORCE_OFF;
 131        else
 132                ret = -EINVAL;
 133
 134        if (old_force != connector->force || !connector->force) {
 135                DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force updated from %d to %d or reprobing\n",
 136                              connector->base.id,
 137                              connector->name,
 138                              old_force, connector->force);
 139
 140                connector->funcs->fill_modes(connector,
 141                                             dev->mode_config.max_width,
 142                                             dev->mode_config.max_height);
 143        }
 144
 145        mutex_unlock(&dev->mode_config.mutex);
 146
 147        return ret ? ret : count;
 148}
 149
 150static ssize_t status_show(struct device *device,
 151                           struct device_attribute *attr,
 152                           char *buf)
 153{
 154        struct drm_connector *connector = to_drm_connector(device);
 155        enum drm_connector_status status;
 156
 157        status = READ_ONCE(connector->status);
 158
 159        return snprintf(buf, PAGE_SIZE, "%s\n",
 160                        drm_get_connector_status_name(status));
 161}
 162
 163static ssize_t dpms_show(struct device *device,
 164                           struct device_attribute *attr,
 165                           char *buf)
 166{
 167        struct drm_connector *connector = to_drm_connector(device);
 168        int dpms;
 169
 170        dpms = READ_ONCE(connector->dpms);
 171
 172        return snprintf(buf, PAGE_SIZE, "%s\n",
 173                        drm_get_dpms_name(dpms));
 174}
 175
 176static ssize_t enabled_show(struct device *device,
 177                            struct device_attribute *attr,
 178                           char *buf)
 179{
 180        struct drm_connector *connector = to_drm_connector(device);
 181        bool enabled;
 182
 183        enabled = READ_ONCE(connector->encoder);
 184
 185        return snprintf(buf, PAGE_SIZE, enabled ? "enabled\n" : "disabled\n");
 186}
 187
 188static ssize_t edid_show(struct file *filp, struct kobject *kobj,
 189                         struct bin_attribute *attr, char *buf, loff_t off,
 190                         size_t count)
 191{
 192        struct device *connector_dev = kobj_to_dev(kobj);
 193        struct drm_connector *connector = to_drm_connector(connector_dev);
 194        unsigned char *edid;
 195        size_t size;
 196        ssize_t ret = 0;
 197
 198        mutex_lock(&connector->dev->mode_config.mutex);
 199        if (!connector->edid_blob_ptr)
 200                goto unlock;
 201
 202        edid = connector->edid_blob_ptr->data;
 203        size = connector->edid_blob_ptr->length;
 204        if (!edid)
 205                goto unlock;
 206
 207        if (off >= size)
 208                goto unlock;
 209
 210        if (off + count > size)
 211                count = size - off;
 212        memcpy(buf, edid + off, count);
 213
 214        ret = count;
 215unlock:
 216        mutex_unlock(&connector->dev->mode_config.mutex);
 217
 218        return ret;
 219}
 220
 221static ssize_t modes_show(struct device *device,
 222                           struct device_attribute *attr,
 223                           char *buf)
 224{
 225        struct drm_connector *connector = to_drm_connector(device);
 226        struct drm_display_mode *mode;
 227        int written = 0;
 228
 229        mutex_lock(&connector->dev->mode_config.mutex);
 230        list_for_each_entry(mode, &connector->modes, head) {
 231                written += snprintf(buf + written, PAGE_SIZE - written, "%s\n",
 232                                    mode->name);
 233        }
 234        mutex_unlock(&connector->dev->mode_config.mutex);
 235
 236        return written;
 237}
 238
 239static DEVICE_ATTR_RW(status);
 240static DEVICE_ATTR_RO(enabled);
 241static DEVICE_ATTR_RO(dpms);
 242static DEVICE_ATTR_RO(modes);
 243
 244static struct attribute *connector_dev_attrs[] = {
 245        &dev_attr_status.attr,
 246        &dev_attr_enabled.attr,
 247        &dev_attr_dpms.attr,
 248        &dev_attr_modes.attr,
 249        NULL
 250};
 251
 252static struct bin_attribute edid_attr = {
 253        .attr.name = "edid",
 254        .attr.mode = 0444,
 255        .size = 0,
 256        .read = edid_show,
 257};
 258
 259static struct bin_attribute *connector_bin_attrs[] = {
 260        &edid_attr,
 261        NULL
 262};
 263
 264static const struct attribute_group connector_dev_group = {
 265        .attrs = connector_dev_attrs,
 266        .bin_attrs = connector_bin_attrs,
 267};
 268
 269static const struct attribute_group *connector_dev_groups[] = {
 270        &connector_dev_group,
 271        NULL
 272};
 273
 274int drm_sysfs_connector_add(struct drm_connector *connector)
 275{
 276        struct drm_device *dev = connector->dev;
 277
 278        if (connector->kdev)
 279                return 0;
 280
 281        connector->kdev =
 282                device_create_with_groups(drm_class, dev->primary->kdev, 0,
 283                                          connector, connector_dev_groups,
 284                                          "card%d-%s", dev->primary->index,
 285                                          connector->name);
 286        DRM_DEBUG("adding \"%s\" to sysfs\n",
 287                  connector->name);
 288
 289        if (IS_ERR(connector->kdev)) {
 290                DRM_ERROR("failed to register connector device: %ld\n", PTR_ERR(connector->kdev));
 291                return PTR_ERR(connector->kdev);
 292        }
 293
 294        /* Let userspace know we have a new connector */
 295        drm_sysfs_hotplug_event(dev);
 296
 297        return 0;
 298}
 299
 300void drm_sysfs_connector_remove(struct drm_connector *connector)
 301{
 302        if (!connector->kdev)
 303                return;
 304        DRM_DEBUG("removing \"%s\" from sysfs\n",
 305                  connector->name);
 306
 307        device_unregister(connector->kdev);
 308        connector->kdev = NULL;
 309}
 310
 311void drm_sysfs_lease_event(struct drm_device *dev)
 312{
 313        char *event_string = "LEASE=1";
 314        char *envp[] = { event_string, NULL };
 315
 316        DRM_DEBUG("generating lease event\n");
 317
 318        kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
 319}
 320
 321/**
 322 * drm_sysfs_hotplug_event - generate a DRM uevent
 323 * @dev: DRM device
 324 *
 325 * Send a uevent for the DRM device specified by @dev.  Currently we only
 326 * set HOTPLUG=1 in the uevent environment, but this could be expanded to
 327 * deal with other types of events.
 328 */
 329void drm_sysfs_hotplug_event(struct drm_device *dev)
 330{
 331        char *event_string = "HOTPLUG=1";
 332        char *envp[] = { event_string, NULL };
 333
 334        DRM_DEBUG("generating hotplug event\n");
 335
 336        kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
 337}
 338EXPORT_SYMBOL(drm_sysfs_hotplug_event);
 339
 340static void drm_sysfs_release(struct device *dev)
 341{
 342        kfree(dev);
 343}
 344
 345struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
 346{
 347        const char *minor_str;
 348        struct device *kdev;
 349        int r;
 350
 351        if (minor->type == DRM_MINOR_RENDER)
 352                minor_str = "renderD%d";
 353        else
 354                minor_str = "card%d";
 355
 356        kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
 357        if (!kdev)
 358                return ERR_PTR(-ENOMEM);
 359
 360        device_initialize(kdev);
 361        kdev->devt = MKDEV(DRM_MAJOR, minor->index);
 362        kdev->class = drm_class;
 363        kdev->type = &drm_sysfs_device_minor;
 364        kdev->parent = minor->dev->dev;
 365        kdev->release = drm_sysfs_release;
 366        dev_set_drvdata(kdev, minor);
 367
 368        r = dev_set_name(kdev, minor_str, minor->index);
 369        if (r < 0)
 370                goto err_free;
 371
 372        return kdev;
 373
 374err_free:
 375        put_device(kdev);
 376        return ERR_PTR(r);
 377}
 378
 379/**
 380 * drm_class_device_register - register new device with the DRM sysfs class
 381 * @dev: device to register
 382 *
 383 * Registers a new &struct device within the DRM sysfs class. Essentially only
 384 * used by ttm to have a place for its global settings. Drivers should never use
 385 * this.
 386 */
 387int drm_class_device_register(struct device *dev)
 388{
 389        if (!drm_class || IS_ERR(drm_class))
 390                return -ENOENT;
 391
 392        dev->class = drm_class;
 393        return device_register(dev);
 394}
 395EXPORT_SYMBOL_GPL(drm_class_device_register);
 396
 397/**
 398 * drm_class_device_unregister - unregister device with the DRM sysfs class
 399 * @dev: device to unregister
 400 *
 401 * Unregisters a &struct device from the DRM sysfs class. Essentially only used
 402 * by ttm to have a place for its global settings. Drivers should never use
 403 * this.
 404 */
 405void drm_class_device_unregister(struct device *dev)
 406{
 407        return device_unregister(dev);
 408}
 409EXPORT_SYMBOL_GPL(drm_class_device_unregister);
 410