LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_sysfs.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 7 163 4.3 %
Date: 2022-12-09 01:23:36 Functions: 1 19 5.3 %

          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);

Generated by: LCOV version 1.14