LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_sysfs.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 9 163 5.5 %
Date: 2022-04-01 14:58:12 Functions: 1 18 5.6 %
Branches: 2 64 3.1 %

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

Generated by: LCOV version 1.14