Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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