linux/drivers/gpu/drm/drm_sysfs.c
<<
>>
Prefs
   1
   2/*
   3 * drm_sysfs.c - Modifications to drm_sysfs_class.c to support
   4 *               extra sysfs attribute from DRM. Normal drm_sysfs_class
   5 *               does not allow adding attributes.
   6 *
   7 * Copyright (c) 2004 Jon Smirl <jonsmirl@gmail.com>
   8 * Copyright (c) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
   9 * Copyright (c) 2003-2004 IBM Corp.
  10 *
  11 * This file is released under the GPLv2
  12 *
  13 */
  14
  15#include <linux/device.h>
  16#include <linux/kdev_t.h>
  17#include <linux/gfp.h>
  18#include <linux/err.h>
  19#include <linux/export.h>
  20
  21#include <drm/drm_sysfs.h>
  22#include <drm/drm_core.h>
  23#include <drm/drmP.h>
  24#include "drm_internal.h"
  25
  26#define to_drm_minor(d) dev_get_drvdata(d)
  27#define to_drm_connector(d) dev_get_drvdata(d)
  28
  29static struct device_type drm_sysfs_device_minor = {
  30        .name = "drm_minor"
  31};
  32
  33struct class *drm_class;
  34
  35static char *drm_devnode(struct device *dev, umode_t *mode)
  36{
  37        return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
  38}
  39
  40static CLASS_ATTR_STRING(version, S_IRUGO,
  41                CORE_NAME " "
  42                __stringify(CORE_MAJOR) "."
  43                __stringify(CORE_MINOR) "."
  44                __stringify(CORE_PATCHLEVEL) " "
  45                CORE_DATE);
  46
  47/**
  48 * drm_sysfs_init - initialize sysfs helpers
  49 *
  50 * This is used to create the DRM class, which is the implicit parent of any
  51 * other top-level DRM sysfs objects.
  52 *
  53 * You must call drm_sysfs_destroy() to release the allocated resources.
  54 *
  55 * Return: 0 on success, negative error code on failure.
  56 */
  57int drm_sysfs_init(void)
  58{
  59        int err;
  60
  61        drm_class = class_create(THIS_MODULE, "drm");
  62        if (IS_ERR(drm_class))
  63                return PTR_ERR(drm_class);
  64
  65        err = class_create_file(drm_class, &class_attr_version.attr);
  66        if (err) {
  67                class_destroy(drm_class);
  68                drm_class = NULL;
  69                return err;
  70        }
  71
  72        drm_class->devnode = drm_devnode;
  73        return 0;
  74}
  75
  76/**
  77 * drm_sysfs_destroy - destroys DRM class
  78 *
  79 * Destroy the DRM device class.
  80 */
  81void drm_sysfs_destroy(void)
  82{
  83        if (IS_ERR_OR_NULL(drm_class))
  84                return;
  85        class_remove_file(drm_class, &class_attr_version.attr);
  86        class_destroy(drm_class);
  87        drm_class = NULL;
  88}
  89
  90/*
  91 * Connector properties
  92 */
  93static ssize_t status_store(struct device *device,
  94                           struct device_attribute *attr,
  95                           const char *buf, size_t count)
  96{
  97        struct drm_connector *connector = to_drm_connector(device);
  98        struct drm_device *dev = connector->dev;
  99        enum drm_connector_force old_force;
 100        int ret;
 101
 102        ret = mutex_lock_interruptible(&dev->mode_config.mutex);
 103        if (ret)
 104                return ret;
 105
 106        old_force = connector->force;
 107
 108        if (sysfs_streq(buf, "detect"))
 109                connector->force = 0;
 110        else if (sysfs_streq(buf, "on"))
 111                connector->force = DRM_FORCE_ON;
 112        else if (sysfs_streq(buf, "on-digital"))
 113                connector->force = DRM_FORCE_ON_DIGITAL;
 114        else if (sysfs_streq(buf, "off"))
 115                connector->force = DRM_FORCE_OFF;
 116        else
 117                ret = -EINVAL;
 118
 119        if (old_force != connector->force || !connector->force) {
 120                DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force updated from %d to %d or reprobing\n",
 121                              connector->base.id,
 122                              connector->name,
 123                              old_force, connector->force);
 124
 125                connector->funcs->fill_modes(connector,
 126                                             dev->mode_config.max_width,
 127                                             dev->mode_config.max_height);
 128        }
 129
 130        mutex_unlock(&dev->mode_config.mutex);
 131
 132        return ret ? ret : count;
 133}
 134
 135static ssize_t status_show(struct device *device,
 136                           struct device_attribute *attr,
 137                           char *buf)
 138{
 139        struct drm_connector *connector = to_drm_connector(device);
 140        enum drm_connector_status status;
 141
 142        status = READ_ONCE(connector->status);
 143
 144        return snprintf(buf, PAGE_SIZE, "%s\n",
 145                        drm_get_connector_status_name(status));
 146}
 147
 148static ssize_t dpms_show(struct device *device,
 149                           struct device_attribute *attr,
 150                           char *buf)
 151{
 152        struct drm_connector *connector = to_drm_connector(device);
 153        int dpms;
 154
 155        dpms = READ_ONCE(connector->dpms);
 156
 157        return snprintf(buf, PAGE_SIZE, "%s\n",
 158                        drm_get_dpms_name(dpms));
 159}
 160
 161static ssize_t enabled_show(struct device *device,
 162                            struct device_attribute *attr,
 163                           char *buf)
 164{
 165        struct drm_connector *connector = to_drm_connector(device);
 166        bool enabled;
 167
 168        enabled = READ_ONCE(connector->encoder);
 169
 170        return snprintf(buf, PAGE_SIZE, enabled ? "enabled\n" : "disabled\n");
 171}
 172
 173static ssize_t edid_show(struct file *filp, struct kobject *kobj,
 174                         struct bin_attribute *attr, char *buf, loff_t off,
 175                         size_t count)
 176{
 177        struct device *connector_dev = kobj_to_dev(kobj);
 178        struct drm_connector *connector = to_drm_connector(connector_dev);
 179        unsigned char *edid;
 180        size_t size;
 181        ssize_t ret = 0;
 182
 183        mutex_lock(&connector->dev->mode_config.mutex);
 184        if (!connector->edid_blob_ptr)
 185                goto unlock;
 186
 187        edid = connector->edid_blob_ptr->data;
 188        size = connector->edid_blob_ptr->length;
 189        if (!edid)
 190                goto unlock;
 191
 192        if (off >= size)
 193                goto unlock;
 194
 195        if (off + count > size)
 196                count = size - off;
 197        memcpy(buf, edid + off, count);
 198
 199        ret = count;
 200unlock:
 201        mutex_unlock(&connector->dev->mode_config.mutex);
 202
 203        return ret;
 204}
 205
 206static ssize_t modes_show(struct device *device,
 207                           struct device_attribute *attr,
 208                           char *buf)
 209{
 210        struct drm_connector *connector = to_drm_connector(device);
 211        struct drm_display_mode *mode;
 212        int written = 0;
 213
 214        mutex_lock(&connector->dev->mode_config.mutex);
 215        list_for_each_entry(mode, &connector->modes, head) {
 216                written += snprintf(buf + written, PAGE_SIZE - written, "%s\n",
 217                                    mode->name);
 218        }
 219        mutex_unlock(&connector->dev->mode_config.mutex);
 220
 221        return written;
 222}
 223
 224static DEVICE_ATTR_RW(status);
 225static DEVICE_ATTR_RO(enabled);
 226static DEVICE_ATTR_RO(dpms);
 227static DEVICE_ATTR_RO(modes);
 228
 229static struct attribute *connector_dev_attrs[] = {
 230        &dev_attr_status.attr,
 231        &dev_attr_enabled.attr,
 232        &dev_attr_dpms.attr,
 233        &dev_attr_modes.attr,
 234        NULL
 235};
 236
 237static struct bin_attribute edid_attr = {
 238        .attr.name = "edid",
 239        .attr.mode = 0444,
 240        .size = 0,
 241        .read = edid_show,
 242};
 243
 244static struct bin_attribute *connector_bin_attrs[] = {
 245        &edid_attr,
 246        NULL
 247};
 248
 249static const struct attribute_group connector_dev_group = {
 250        .attrs = connector_dev_attrs,
 251        .bin_attrs = connector_bin_attrs,
 252};
 253
 254static const struct attribute_group *connector_dev_groups[] = {
 255        &connector_dev_group,
 256        NULL
 257};
 258
 259/**
 260 * drm_sysfs_connector_add - add a connector to sysfs
 261 * @connector: connector to add
 262 *
 263 * Create a connector device in sysfs, along with its associated connector
 264 * properties (so far, connection status, dpms, mode list & edid) and
 265 * generate a hotplug event so userspace knows there's a new connector
 266 * available.
 267 */
 268int drm_sysfs_connector_add(struct drm_connector *connector)
 269{
 270        struct drm_device *dev = connector->dev;
 271
 272        if (connector->kdev)
 273                return 0;
 274
 275        connector->kdev =
 276                device_create_with_groups(drm_class, dev->primary->kdev, 0,
 277                                          connector, connector_dev_groups,
 278                                          "card%d-%s", dev->primary->index,
 279                                          connector->name);
 280        DRM_DEBUG("adding \"%s\" to sysfs\n",
 281                  connector->name);
 282
 283        if (IS_ERR(connector->kdev)) {
 284                DRM_ERROR("failed to register connector device: %ld\n", PTR_ERR(connector->kdev));
 285                return PTR_ERR(connector->kdev);
 286        }
 287
 288        /* Let userspace know we have a new connector */
 289        drm_sysfs_hotplug_event(dev);
 290
 291        return 0;
 292}
 293
 294/**
 295 * drm_sysfs_connector_remove - remove an connector device from sysfs
 296 * @connector: connector to remove
 297 *
 298 * Remove @connector and its associated attributes from sysfs.  Note that
 299 * the device model core will take care of sending the "remove" uevent
 300 * at this time, so we don't need to do it.
 301 *
 302 * Note:
 303 * This routine should only be called if the connector was previously
 304 * successfully registered.  If @connector hasn't been registered yet,
 305 * you'll likely see a panic somewhere deep in sysfs code when called.
 306 */
 307void drm_sysfs_connector_remove(struct drm_connector *connector)
 308{
 309        if (!connector->kdev)
 310                return;
 311        DRM_DEBUG("removing \"%s\" from sysfs\n",
 312                  connector->name);
 313
 314        device_unregister(connector->kdev);
 315        connector->kdev = NULL;
 316}
 317
 318/**
 319 * drm_sysfs_hotplug_event - generate a DRM uevent
 320 * @dev: DRM device
 321 *
 322 * Send a uevent for the DRM device specified by @dev.  Currently we only
 323 * set HOTPLUG=1 in the uevent environment, but this could be expanded to
 324 * deal with other types of events.
 325 */
 326void drm_sysfs_hotplug_event(struct drm_device *dev)
 327{
 328        char *event_string = "HOTPLUG=1";
 329        char *envp[] = { event_string, NULL };
 330
 331        DRM_DEBUG("generating hotplug event\n");
 332
 333        kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
 334}
 335EXPORT_SYMBOL(drm_sysfs_hotplug_event);
 336
 337static void drm_sysfs_release(struct device *dev)
 338{
 339        kfree(dev);
 340}
 341
 342/**
 343 * drm_sysfs_minor_alloc() - Allocate sysfs device for given minor
 344 * @minor: minor to allocate sysfs device for
 345 *
 346 * This allocates a new sysfs device for @minor and returns it. The device is
 347 * not registered nor linked. The caller has to use device_add() and
 348 * device_del() to register and unregister it.
 349 *
 350 * Note that dev_get_drvdata() on the new device will return the minor.
 351 * However, the device does not hold a ref-count to the minor nor to the
 352 * underlying drm_device. This is unproblematic as long as you access the
 353 * private data only in sysfs callbacks. device_del() disables those
 354 * synchronously, so they cannot be called after you cleanup a minor.
 355 */
 356struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
 357{
 358        const char *minor_str;
 359        struct device *kdev;
 360        int r;
 361
 362        if (minor->type == DRM_MINOR_CONTROL)
 363                minor_str = "controlD%d";
 364        else if (minor->type == DRM_MINOR_RENDER)
 365                minor_str = "renderD%d";
 366        else
 367                minor_str = "card%d";
 368
 369        kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
 370        if (!kdev)
 371                return ERR_PTR(-ENOMEM);
 372
 373        device_initialize(kdev);
 374        kdev->devt = MKDEV(DRM_MAJOR, minor->index);
 375        kdev->class = drm_class;
 376        kdev->type = &drm_sysfs_device_minor;
 377        kdev->parent = minor->dev->dev;
 378        kdev->release = drm_sysfs_release;
 379        dev_set_drvdata(kdev, minor);
 380
 381        r = dev_set_name(kdev, minor_str, minor->index);
 382        if (r < 0)
 383                goto err_free;
 384
 385        return kdev;
 386
 387err_free:
 388        put_device(kdev);
 389        return ERR_PTR(r);
 390}
 391
 392/**
 393 * drm_class_device_register - Register a struct device in the drm class.
 394 *
 395 * @dev: pointer to struct device to register.
 396 *
 397 * @dev should have all relevant members pre-filled with the exception
 398 * of the class member. In particular, the device_type member must
 399 * be set.
 400 */
 401
 402int drm_class_device_register(struct device *dev)
 403{
 404        if (!drm_class || IS_ERR(drm_class))
 405                return -ENOENT;
 406
 407        dev->class = drm_class;
 408        return device_register(dev);
 409}
 410EXPORT_SYMBOL_GPL(drm_class_device_register);
 411
 412void drm_class_device_unregister(struct device *dev)
 413{
 414        return device_unregister(dev);
 415}
 416EXPORT_SYMBOL_GPL(drm_class_device_unregister);
 417