155716d26SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2c0e09200SDave Airlie 3c0e09200SDave Airlie /* 4c0e09200SDave Airlie * drm_sysfs.c - Modifications to drm_sysfs_class.c to support 5c0e09200SDave Airlie * extra sysfs attribute from DRM. Normal drm_sysfs_class 6c0e09200SDave Airlie * does not allow adding attributes. 7c0e09200SDave Airlie * 8c0e09200SDave Airlie * Copyright (c) 2004 Jon Smirl <jonsmirl@gmail.com> 9c0e09200SDave Airlie * Copyright (c) 2003-2004 Greg Kroah-Hartman <greg@kroah.com> 10c0e09200SDave Airlie * Copyright (c) 2003-2004 IBM Corp. 11c0e09200SDave Airlie */ 12c0e09200SDave Airlie 1348c429c6SHans de Goede #include <linux/acpi.h> 14c0e09200SDave Airlie #include <linux/device.h> 15c0e09200SDave Airlie #include <linux/err.h> 162d1a8a48SPaul Gortmaker #include <linux/export.h> 170500c04eSSam Ravnborg #include <linux/gfp.h> 18e1a29c6cSAndrzej Pietrasiewicz #include <linux/i2c.h> 190500c04eSSam Ravnborg #include <linux/kdev_t.h> 200500c04eSSam Ravnborg #include <linux/slab.h> 21c0e09200SDave Airlie 220500c04eSSam Ravnborg #include <drm/drm_connector.h> 230500c04eSSam Ravnborg #include <drm/drm_device.h> 240500c04eSSam Ravnborg #include <drm/drm_file.h> 250500c04eSSam Ravnborg #include <drm/drm_modes.h> 260500c04eSSam Ravnborg #include <drm/drm_print.h> 270500c04eSSam Ravnborg #include <drm/drm_property.h> 28760285e7SDavid Howells #include <drm/drm_sysfs.h> 290500c04eSSam Ravnborg 3067d0ec4eSDaniel Vetter #include "drm_internal.h" 316fe2ce06SRamalingam C #include "drm_crtc_internal.h" 32c0e09200SDave Airlie 335bdebb18SDave Airlie #define to_drm_minor(d) dev_get_drvdata(d) 345bdebb18SDave Airlie #define to_drm_connector(d) dev_get_drvdata(d) 35c0e09200SDave Airlie 36e2271704SDaniel Vetter /** 37e2271704SDaniel Vetter * DOC: overview 38e2271704SDaniel Vetter * 39e2271704SDaniel Vetter * DRM provides very little additional support to drivers for sysfs 40e2271704SDaniel Vetter * interactions, beyond just all the standard stuff. Drivers who want to expose 41e2271704SDaniel Vetter * additional sysfs properties and property groups can attach them at either 42e2271704SDaniel Vetter * &drm_device.dev or &drm_connector.kdev. 43e2271704SDaniel Vetter * 44e2271704SDaniel Vetter * Registration is automatically handled when calling drm_dev_register(), or 45e2271704SDaniel Vetter * drm_connector_register() in case of hot-plugged connectors. Unregistration is 46e2271704SDaniel Vetter * also automatically handled by drm_dev_unregister() and 47e2271704SDaniel Vetter * drm_connector_unregister(). 48e2271704SDaniel Vetter */ 49e2271704SDaniel Vetter 5008e4d534SThomas Hellstrom static struct device_type drm_sysfs_device_minor = { 5108e4d534SThomas Hellstrom .name = "drm_minor" 5208e4d534SThomas Hellstrom }; 5308e4d534SThomas Hellstrom 54331de7dbSHans de Goede static struct device_type drm_sysfs_device_connector = { 55331de7dbSHans de Goede .name = "drm_connector", 56331de7dbSHans de Goede }; 57331de7dbSHans de Goede 58fcc90213SDavid Herrmann struct class *drm_class; 59fcc90213SDavid Herrmann 6048c429c6SHans de Goede #ifdef CONFIG_ACPI 6148c429c6SHans de Goede static bool drm_connector_acpi_bus_match(struct device *dev) 6248c429c6SHans de Goede { 6348c429c6SHans de Goede return dev->type == &drm_sysfs_device_connector; 6448c429c6SHans de Goede } 6548c429c6SHans de Goede 6648c429c6SHans de Goede static struct acpi_device *drm_connector_acpi_find_companion(struct device *dev) 6748c429c6SHans de Goede { 6848c429c6SHans de Goede struct drm_connector *connector = to_drm_connector(dev); 6948c429c6SHans de Goede 7048c429c6SHans de Goede return to_acpi_device_node(connector->fwnode); 7148c429c6SHans de Goede } 7248c429c6SHans de Goede 7348c429c6SHans de Goede static struct acpi_bus_type drm_connector_acpi_bus = { 7448c429c6SHans de Goede .name = "drm_connector", 7548c429c6SHans de Goede .match = drm_connector_acpi_bus_match, 7648c429c6SHans de Goede .find_companion = drm_connector_acpi_find_companion, 7748c429c6SHans de Goede }; 7848c429c6SHans de Goede 7948c429c6SHans de Goede static void drm_sysfs_acpi_register(void) 8048c429c6SHans de Goede { 8148c429c6SHans de Goede register_acpi_bus_type(&drm_connector_acpi_bus); 8248c429c6SHans de Goede } 8348c429c6SHans de Goede 8448c429c6SHans de Goede static void drm_sysfs_acpi_unregister(void) 8548c429c6SHans de Goede { 8648c429c6SHans de Goede unregister_acpi_bus_type(&drm_connector_acpi_bus); 8748c429c6SHans de Goede } 8848c429c6SHans de Goede #else 8948c429c6SHans de Goede static void drm_sysfs_acpi_register(void) { } 9048c429c6SHans de Goede static void drm_sysfs_acpi_unregister(void) { } 9148c429c6SHans de Goede #endif 9248c429c6SHans de Goede 93*ff62b8e6SGreg Kroah-Hartman static char *drm_devnode(const struct device *dev, umode_t *mode) 9402200d06SKay Sievers { 9502200d06SKay Sievers return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); 9602200d06SKay Sievers } 9702200d06SKay Sievers 9882d5e73fSDavid Herrmann static CLASS_ATTR_STRING(version, S_IRUGO, "drm 1.1.0 20060810"); 99c0e09200SDave Airlie 100c0e09200SDave Airlie /** 101fcc90213SDavid Herrmann * drm_sysfs_init - initialize sysfs helpers 102c0e09200SDave Airlie * 103fcc90213SDavid Herrmann * This is used to create the DRM class, which is the implicit parent of any 104fcc90213SDavid Herrmann * other top-level DRM sysfs objects. 105c0e09200SDave Airlie * 106fcc90213SDavid Herrmann * You must call drm_sysfs_destroy() to release the allocated resources. 107fcc90213SDavid Herrmann * 108fcc90213SDavid Herrmann * Return: 0 on success, negative error code on failure. 109c0e09200SDave Airlie */ 110fcc90213SDavid Herrmann int drm_sysfs_init(void) 111c0e09200SDave Airlie { 112c0e09200SDave Airlie int err; 113c0e09200SDave Airlie 114fcc90213SDavid Herrmann drm_class = class_create(THIS_MODULE, "drm"); 115fcc90213SDavid Herrmann if (IS_ERR(drm_class)) 116fcc90213SDavid Herrmann return PTR_ERR(drm_class); 117fcc90213SDavid Herrmann 118fcc90213SDavid Herrmann err = class_create_file(drm_class, &class_attr_version.attr); 119fcc90213SDavid Herrmann if (err) { 120fcc90213SDavid Herrmann class_destroy(drm_class); 121fcc90213SDavid Herrmann drm_class = NULL; 122fcc90213SDavid Herrmann return err; 123c0e09200SDave Airlie } 124c0e09200SDave Airlie 125fcc90213SDavid Herrmann drm_class->devnode = drm_devnode; 12648c429c6SHans de Goede 12748c429c6SHans de Goede drm_sysfs_acpi_register(); 128fcc90213SDavid Herrmann return 0; 129c0e09200SDave Airlie } 130c0e09200SDave Airlie 131c0e09200SDave Airlie /** 132c0e09200SDave Airlie * drm_sysfs_destroy - destroys DRM class 133c0e09200SDave Airlie * 134c0e09200SDave Airlie * Destroy the DRM device class. 135c0e09200SDave Airlie */ 136c0e09200SDave Airlie void drm_sysfs_destroy(void) 137c0e09200SDave Airlie { 13826b91ae4SDavid Herrmann if (IS_ERR_OR_NULL(drm_class)) 139c0e09200SDave Airlie return; 14048c429c6SHans de Goede drm_sysfs_acpi_unregister(); 1410933e2d9SAndi Kleen class_remove_file(drm_class, &class_attr_version.attr); 142c0e09200SDave Airlie class_destroy(drm_class); 14349099c49SDave Airlie drm_class = NULL; 144c0e09200SDave Airlie } 145c0e09200SDave Airlie 146331de7dbSHans de Goede static void drm_sysfs_release(struct device *dev) 147331de7dbSHans de Goede { 148331de7dbSHans de Goede kfree(dev); 149331de7dbSHans de Goede } 150331de7dbSHans de Goede 151f453ba04SDave Airlie /* 152f453ba04SDave Airlie * Connector properties 153f453ba04SDave Airlie */ 154c484f02dSChris Wilson static ssize_t status_store(struct device *device, 155c484f02dSChris Wilson struct device_attribute *attr, 156c484f02dSChris Wilson const char *buf, size_t count) 157c484f02dSChris Wilson { 158c484f02dSChris Wilson struct drm_connector *connector = to_drm_connector(device); 159c484f02dSChris Wilson struct drm_device *dev = connector->dev; 160ed293f77SDaniel Vetter enum drm_connector_force old_force; 161c484f02dSChris Wilson int ret; 162c484f02dSChris Wilson 163c484f02dSChris Wilson ret = mutex_lock_interruptible(&dev->mode_config.mutex); 164c484f02dSChris Wilson if (ret) 165c484f02dSChris Wilson return ret; 166c484f02dSChris Wilson 167ed293f77SDaniel Vetter old_force = connector->force; 168c484f02dSChris Wilson 169ed293f77SDaniel Vetter if (sysfs_streq(buf, "detect")) 170c484f02dSChris Wilson connector->force = 0; 171ed293f77SDaniel Vetter else if (sysfs_streq(buf, "on")) 172c484f02dSChris Wilson connector->force = DRM_FORCE_ON; 173ed293f77SDaniel Vetter else if (sysfs_streq(buf, "on-digital")) 174c484f02dSChris Wilson connector->force = DRM_FORCE_ON_DIGITAL; 175ed293f77SDaniel Vetter else if (sysfs_streq(buf, "off")) 176c484f02dSChris Wilson connector->force = DRM_FORCE_OFF; 177ed293f77SDaniel Vetter else 178c484f02dSChris Wilson ret = -EINVAL; 179c484f02dSChris Wilson 180ed293f77SDaniel Vetter if (old_force != connector->force || !connector->force) { 181ed293f77SDaniel Vetter DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force updated from %d to %d or reprobing\n", 182c484f02dSChris Wilson connector->base.id, 183c484f02dSChris Wilson connector->name, 184ed293f77SDaniel Vetter old_force, connector->force); 185c484f02dSChris Wilson 186ed293f77SDaniel Vetter connector->funcs->fill_modes(connector, 187ed293f77SDaniel Vetter dev->mode_config.max_width, 188ed293f77SDaniel Vetter dev->mode_config.max_height); 189c484f02dSChris Wilson } 190c484f02dSChris Wilson 191c484f02dSChris Wilson mutex_unlock(&dev->mode_config.mutex); 192c484f02dSChris Wilson 19338d8571dSRussell King return ret ? ret : count; 194c484f02dSChris Wilson } 195c484f02dSChris Wilson 196f453ba04SDave Airlie static ssize_t status_show(struct device *device, 197f453ba04SDave Airlie struct device_attribute *attr, 198f453ba04SDave Airlie char *buf) 199f453ba04SDave Airlie { 200f453ba04SDave Airlie struct drm_connector *connector = to_drm_connector(device); 2014eb9b945SDaniel Vetter enum drm_connector_status status; 2024eb9b945SDaniel Vetter 2034eb9b945SDaniel Vetter status = READ_ONCE(connector->status); 204007c80a5SChris Wilson 205835bc483STian Tao return sysfs_emit(buf, "%s\n", 2064eb9b945SDaniel Vetter drm_get_connector_status_name(status)); 207f453ba04SDave Airlie } 208f453ba04SDave Airlie 209f453ba04SDave Airlie static ssize_t dpms_show(struct device *device, 210f453ba04SDave Airlie struct device_attribute *attr, 211f453ba04SDave Airlie char *buf) 212f453ba04SDave Airlie { 213f453ba04SDave Airlie struct drm_connector *connector = to_drm_connector(device); 214621bd0f6SDaniel Vetter int dpms; 215f453ba04SDave Airlie 216621bd0f6SDaniel Vetter dpms = READ_ONCE(connector->dpms); 217f453ba04SDave Airlie 218835bc483STian Tao return sysfs_emit(buf, "%s\n", drm_get_dpms_name(dpms)); 219f453ba04SDave Airlie } 220f453ba04SDave Airlie 221f453ba04SDave Airlie static ssize_t enabled_show(struct device *device, 222f453ba04SDave Airlie struct device_attribute *attr, 223f453ba04SDave Airlie char *buf) 224f453ba04SDave Airlie { 225f453ba04SDave Airlie struct drm_connector *connector = to_drm_connector(device); 2264eb9b945SDaniel Vetter bool enabled; 227f453ba04SDave Airlie 2284eb9b945SDaniel Vetter enabled = READ_ONCE(connector->encoder); 2294eb9b945SDaniel Vetter 230835bc483STian Tao return sysfs_emit(buf, enabled ? "enabled\n" : "disabled\n"); 231f453ba04SDave Airlie } 232f453ba04SDave Airlie 2332c3c8beaSChris Wright static ssize_t edid_show(struct file *filp, struct kobject *kobj, 2342c3c8beaSChris Wright struct bin_attribute *attr, char *buf, loff_t off, 2352c3c8beaSChris Wright size_t count) 236f453ba04SDave Airlie { 237d122cbf1SGeliang Tang struct device *connector_dev = kobj_to_dev(kobj); 238f453ba04SDave Airlie struct drm_connector *connector = to_drm_connector(connector_dev); 239f453ba04SDave Airlie unsigned char *edid; 240f453ba04SDave Airlie size_t size; 241a48a62bcSDaniel Vetter ssize_t ret = 0; 242f453ba04SDave Airlie 243a48a62bcSDaniel Vetter mutex_lock(&connector->dev->mode_config.mutex); 244f453ba04SDave Airlie if (!connector->edid_blob_ptr) 245a48a62bcSDaniel Vetter goto unlock; 246f453ba04SDave Airlie 247f453ba04SDave Airlie edid = connector->edid_blob_ptr->data; 248f453ba04SDave Airlie size = connector->edid_blob_ptr->length; 249f453ba04SDave Airlie if (!edid) 250a48a62bcSDaniel Vetter goto unlock; 251f453ba04SDave Airlie 252f453ba04SDave Airlie if (off >= size) 253a48a62bcSDaniel Vetter goto unlock; 254f453ba04SDave Airlie 255f453ba04SDave Airlie if (off + count > size) 256f453ba04SDave Airlie count = size - off; 257f453ba04SDave Airlie memcpy(buf, edid + off, count); 258f453ba04SDave Airlie 259a48a62bcSDaniel Vetter ret = count; 260a48a62bcSDaniel Vetter unlock: 261a48a62bcSDaniel Vetter mutex_unlock(&connector->dev->mode_config.mutex); 262a48a62bcSDaniel Vetter 263a48a62bcSDaniel Vetter return ret; 264f453ba04SDave Airlie } 265f453ba04SDave Airlie 266f453ba04SDave Airlie static ssize_t modes_show(struct device *device, 267f453ba04SDave Airlie struct device_attribute *attr, 268f453ba04SDave Airlie char *buf) 269f453ba04SDave Airlie { 270f453ba04SDave Airlie struct drm_connector *connector = to_drm_connector(device); 271f453ba04SDave Airlie struct drm_display_mode *mode; 272f453ba04SDave Airlie int written = 0; 273f453ba04SDave Airlie 274a48a62bcSDaniel Vetter mutex_lock(&connector->dev->mode_config.mutex); 275f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) { 2769b9f2219STakashi Iwai written += scnprintf(buf + written, PAGE_SIZE - written, "%s\n", 277f453ba04SDave Airlie mode->name); 278f453ba04SDave Airlie } 279a48a62bcSDaniel Vetter mutex_unlock(&connector->dev->mode_config.mutex); 280f453ba04SDave Airlie 281f453ba04SDave Airlie return written; 282f453ba04SDave Airlie } 283f453ba04SDave Airlie 284c484f02dSChris Wilson static DEVICE_ATTR_RW(status); 285335f1a62STakashi Iwai static DEVICE_ATTR_RO(enabled); 286335f1a62STakashi Iwai static DEVICE_ATTR_RO(dpms); 287335f1a62STakashi Iwai static DEVICE_ATTR_RO(modes); 288335f1a62STakashi Iwai 289335f1a62STakashi Iwai static struct attribute *connector_dev_attrs[] = { 290335f1a62STakashi Iwai &dev_attr_status.attr, 291335f1a62STakashi Iwai &dev_attr_enabled.attr, 292335f1a62STakashi Iwai &dev_attr_dpms.attr, 293335f1a62STakashi Iwai &dev_attr_modes.attr, 294335f1a62STakashi Iwai NULL 295f453ba04SDave Airlie }; 296f453ba04SDave Airlie 297f453ba04SDave Airlie static struct bin_attribute edid_attr = { 298f453ba04SDave Airlie .attr.name = "edid", 299e36ebaf4SKeith Packard .attr.mode = 0444, 3007466f4ccSAdam Jackson .size = 0, 301f453ba04SDave Airlie .read = edid_show, 302f453ba04SDave Airlie }; 303f453ba04SDave Airlie 304335f1a62STakashi Iwai static struct bin_attribute *connector_bin_attrs[] = { 305335f1a62STakashi Iwai &edid_attr, 306335f1a62STakashi Iwai NULL 307335f1a62STakashi Iwai }; 308335f1a62STakashi Iwai 309335f1a62STakashi Iwai static const struct attribute_group connector_dev_group = { 310335f1a62STakashi Iwai .attrs = connector_dev_attrs, 311335f1a62STakashi Iwai .bin_attrs = connector_bin_attrs, 312335f1a62STakashi Iwai }; 313335f1a62STakashi Iwai 314335f1a62STakashi Iwai static const struct attribute_group *connector_dev_groups[] = { 315335f1a62STakashi Iwai &connector_dev_group, 316335f1a62STakashi Iwai NULL 317335f1a62STakashi Iwai }; 318335f1a62STakashi Iwai 319f453ba04SDave Airlie int drm_sysfs_connector_add(struct drm_connector *connector) 320f453ba04SDave Airlie { 321f453ba04SDave Airlie struct drm_device *dev = connector->dev; 322331de7dbSHans de Goede struct device *kdev; 323331de7dbSHans de Goede int r; 324f453ba04SDave Airlie 3255bdebb18SDave Airlie if (connector->kdev) 3265bdebb18SDave Airlie return 0; 3275bdebb18SDave Airlie 328331de7dbSHans de Goede kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); 329331de7dbSHans de Goede if (!kdev) 330331de7dbSHans de Goede return -ENOMEM; 331331de7dbSHans de Goede 332331de7dbSHans de Goede device_initialize(kdev); 333331de7dbSHans de Goede kdev->class = drm_class; 334331de7dbSHans de Goede kdev->type = &drm_sysfs_device_connector; 335331de7dbSHans de Goede kdev->parent = dev->primary->kdev; 336331de7dbSHans de Goede kdev->groups = connector_dev_groups; 337331de7dbSHans de Goede kdev->release = drm_sysfs_release; 338331de7dbSHans de Goede dev_set_drvdata(kdev, connector); 339331de7dbSHans de Goede 340331de7dbSHans de Goede r = dev_set_name(kdev, "card%d-%s", dev->primary->index, connector->name); 341331de7dbSHans de Goede if (r) 342331de7dbSHans de Goede goto err_free; 343331de7dbSHans de Goede 344f453ba04SDave Airlie DRM_DEBUG("adding \"%s\" to sysfs\n", 34525933820SJani Nikula connector->name); 346f453ba04SDave Airlie 347331de7dbSHans de Goede r = device_add(kdev); 348331de7dbSHans de Goede if (r) { 349331de7dbSHans de Goede drm_err(dev, "failed to register connector device: %d\n", r); 350331de7dbSHans de Goede goto err_free; 351f453ba04SDave Airlie } 352f453ba04SDave Airlie 353331de7dbSHans de Goede connector->kdev = kdev; 354331de7dbSHans de Goede 355e1a29c6cSAndrzej Pietrasiewicz if (connector->ddc) 356e1a29c6cSAndrzej Pietrasiewicz return sysfs_create_link(&connector->kdev->kobj, 357e1a29c6cSAndrzej Pietrasiewicz &connector->ddc->dev.kobj, "ddc"); 358f453ba04SDave Airlie return 0; 359331de7dbSHans de Goede 360331de7dbSHans de Goede err_free: 361331de7dbSHans de Goede put_device(kdev); 362331de7dbSHans de Goede return r; 363f453ba04SDave Airlie } 364f453ba04SDave Airlie 365f453ba04SDave Airlie void drm_sysfs_connector_remove(struct drm_connector *connector) 366f453ba04SDave Airlie { 3675bdebb18SDave Airlie if (!connector->kdev) 3681828fe6cSDave Airlie return; 369e1a29c6cSAndrzej Pietrasiewicz 370e1a29c6cSAndrzej Pietrasiewicz if (connector->ddc) 371e1a29c6cSAndrzej Pietrasiewicz sysfs_remove_link(&connector->kdev->kobj, "ddc"); 372e1a29c6cSAndrzej Pietrasiewicz 373f453ba04SDave Airlie DRM_DEBUG("removing \"%s\" from sysfs\n", 37425933820SJani Nikula connector->name); 375f453ba04SDave Airlie 3765bdebb18SDave Airlie device_unregister(connector->kdev); 3775bdebb18SDave Airlie connector->kdev = NULL; 378f453ba04SDave Airlie } 379f453ba04SDave Airlie 380ce858828SDaniel Vetter void drm_sysfs_lease_event(struct drm_device *dev) 381ce858828SDaniel Vetter { 382ce858828SDaniel Vetter char *event_string = "LEASE=1"; 383ce858828SDaniel Vetter char *envp[] = { event_string, NULL }; 384ce858828SDaniel Vetter 385ce858828SDaniel Vetter DRM_DEBUG("generating lease event\n"); 386ce858828SDaniel Vetter 387ce858828SDaniel Vetter kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp); 388ce858828SDaniel Vetter } 389ce858828SDaniel Vetter 390f453ba04SDave Airlie /** 391f453ba04SDave Airlie * drm_sysfs_hotplug_event - generate a DRM uevent 392f453ba04SDave Airlie * @dev: DRM device 393f453ba04SDave Airlie * 394f453ba04SDave Airlie * Send a uevent for the DRM device specified by @dev. Currently we only 395f453ba04SDave Airlie * set HOTPLUG=1 in the uevent environment, but this could be expanded to 396f453ba04SDave Airlie * deal with other types of events. 3976fe2ce06SRamalingam C * 3986fe2ce06SRamalingam C * Any new uapi should be using the drm_sysfs_connector_status_event() 3996fe2ce06SRamalingam C * for uevents on connector status change. 400f453ba04SDave Airlie */ 401f453ba04SDave Airlie void drm_sysfs_hotplug_event(struct drm_device *dev) 402f453ba04SDave Airlie { 403f453ba04SDave Airlie char *event_string = "HOTPLUG=1"; 404f453ba04SDave Airlie char *envp[] = { event_string, NULL }; 405f453ba04SDave Airlie 406f453ba04SDave Airlie DRM_DEBUG("generating hotplug event\n"); 407f453ba04SDave Airlie 4085bdebb18SDave Airlie kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp); 409f453ba04SDave Airlie } 4105ca58282SJesse Barnes EXPORT_SYMBOL(drm_sysfs_hotplug_event); 411f453ba04SDave Airlie 4126fe2ce06SRamalingam C /** 4130d6a8c5eSSimon Ser * drm_sysfs_connector_hotplug_event - generate a DRM uevent for any connector 4140d6a8c5eSSimon Ser * change 4150d6a8c5eSSimon Ser * @connector: connector which has changed 4160d6a8c5eSSimon Ser * 4170d6a8c5eSSimon Ser * Send a uevent for the DRM connector specified by @connector. This will send 4180d6a8c5eSSimon Ser * a uevent with the properties HOTPLUG=1 and CONNECTOR. 4190d6a8c5eSSimon Ser */ 4200d6a8c5eSSimon Ser void drm_sysfs_connector_hotplug_event(struct drm_connector *connector) 4210d6a8c5eSSimon Ser { 4220d6a8c5eSSimon Ser struct drm_device *dev = connector->dev; 4230d6a8c5eSSimon Ser char hotplug_str[] = "HOTPLUG=1", conn_id[21]; 4240d6a8c5eSSimon Ser char *envp[] = { hotplug_str, conn_id, NULL }; 4250d6a8c5eSSimon Ser 4260d6a8c5eSSimon Ser snprintf(conn_id, sizeof(conn_id), 4270d6a8c5eSSimon Ser "CONNECTOR=%u", connector->base.id); 4280d6a8c5eSSimon Ser 4290d6a8c5eSSimon Ser drm_dbg_kms(connector->dev, 4300d6a8c5eSSimon Ser "[CONNECTOR:%d:%s] generating connector hotplug event\n", 4310d6a8c5eSSimon Ser connector->base.id, connector->name); 4320d6a8c5eSSimon Ser 4330d6a8c5eSSimon Ser kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp); 4340d6a8c5eSSimon Ser } 4350d6a8c5eSSimon Ser EXPORT_SYMBOL(drm_sysfs_connector_hotplug_event); 4360d6a8c5eSSimon Ser 4370d6a8c5eSSimon Ser /** 4386fe2ce06SRamalingam C * drm_sysfs_connector_status_event - generate a DRM uevent for connector 4396fe2ce06SRamalingam C * property status change 4406fe2ce06SRamalingam C * @connector: connector on which property status changed 4416fe2ce06SRamalingam C * @property: connector property whose status changed. 4426fe2ce06SRamalingam C * 4436fe2ce06SRamalingam C * Send a uevent for the DRM device specified by @dev. Currently we 4446fe2ce06SRamalingam C * set HOTPLUG=1 and connector id along with the attached property id 4456fe2ce06SRamalingam C * related to the status change. 4466fe2ce06SRamalingam C */ 4476fe2ce06SRamalingam C void drm_sysfs_connector_status_event(struct drm_connector *connector, 4486fe2ce06SRamalingam C struct drm_property *property) 4496fe2ce06SRamalingam C { 4506fe2ce06SRamalingam C struct drm_device *dev = connector->dev; 4516fe2ce06SRamalingam C char hotplug_str[] = "HOTPLUG=1", conn_id[21], prop_id[21]; 4526fe2ce06SRamalingam C char *envp[4] = { hotplug_str, conn_id, prop_id, NULL }; 4536fe2ce06SRamalingam C 4546fe2ce06SRamalingam C WARN_ON(!drm_mode_obj_find_prop_id(&connector->base, 4556fe2ce06SRamalingam C property->base.id)); 4566fe2ce06SRamalingam C 4576fe2ce06SRamalingam C snprintf(conn_id, ARRAY_SIZE(conn_id), 4586fe2ce06SRamalingam C "CONNECTOR=%u", connector->base.id); 4596fe2ce06SRamalingam C snprintf(prop_id, ARRAY_SIZE(prop_id), 4606fe2ce06SRamalingam C "PROPERTY=%u", property->base.id); 4616fe2ce06SRamalingam C 4626fe2ce06SRamalingam C DRM_DEBUG("generating connector status event\n"); 4636fe2ce06SRamalingam C 4646fe2ce06SRamalingam C kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp); 4656fe2ce06SRamalingam C } 4666fe2ce06SRamalingam C EXPORT_SYMBOL(drm_sysfs_connector_status_event); 4676fe2ce06SRamalingam C 468e1728075SDavid Herrmann struct device *drm_sysfs_minor_alloc(struct drm_minor *minor) 469c0e09200SDave Airlie { 470e1728075SDavid Herrmann const char *minor_str; 471e1728075SDavid Herrmann struct device *kdev; 472760c960bSDavid Herrmann int r; 473c0e09200SDave Airlie 4740d49f303SDaniel Vetter if (minor->type == DRM_MINOR_RENDER) 475f453ba04SDave Airlie minor_str = "renderD%d"; 476f453ba04SDave Airlie else 477c0e09200SDave Airlie minor_str = "card%d"; 478c0e09200SDave Airlie 479e1728075SDavid Herrmann kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); 480e1728075SDavid Herrmann if (!kdev) 481e1728075SDavid Herrmann return ERR_PTR(-ENOMEM); 482760c960bSDavid Herrmann 483e1728075SDavid Herrmann device_initialize(kdev); 484e1728075SDavid Herrmann kdev->devt = MKDEV(DRM_MAJOR, minor->index); 485e1728075SDavid Herrmann kdev->class = drm_class; 486e1728075SDavid Herrmann kdev->type = &drm_sysfs_device_minor; 487e1728075SDavid Herrmann kdev->parent = minor->dev->dev; 488e1728075SDavid Herrmann kdev->release = drm_sysfs_release; 489e1728075SDavid Herrmann dev_set_drvdata(kdev, minor); 490760c960bSDavid Herrmann 491e1728075SDavid Herrmann r = dev_set_name(kdev, minor_str, minor->index); 492760c960bSDavid Herrmann if (r < 0) 493e1728075SDavid Herrmann goto err_free; 494760c960bSDavid Herrmann 495e1728075SDavid Herrmann return kdev; 496760c960bSDavid Herrmann 497e1728075SDavid Herrmann err_free: 498e1728075SDavid Herrmann put_device(kdev); 499e1728075SDavid Herrmann return ERR_PTR(r); 500c0e09200SDave Airlie } 501c0e09200SDave Airlie 502c0e09200SDave Airlie /** 503e2271704SDaniel Vetter * drm_class_device_register - register new device with the DRM sysfs class 504e2271704SDaniel Vetter * @dev: device to register 505327c225bSThomas Hellstrom * 506e2271704SDaniel Vetter * Registers a new &struct device within the DRM sysfs class. Essentially only 507e2271704SDaniel Vetter * used by ttm to have a place for its global settings. Drivers should never use 508e2271704SDaniel Vetter * this. 509327c225bSThomas Hellstrom */ 510327c225bSThomas Hellstrom int drm_class_device_register(struct device *dev) 511327c225bSThomas Hellstrom { 51249099c49SDave Airlie if (!drm_class || IS_ERR(drm_class)) 51349099c49SDave Airlie return -ENOENT; 51449099c49SDave Airlie 515327c225bSThomas Hellstrom dev->class = drm_class; 516327c225bSThomas Hellstrom return device_register(dev); 517327c225bSThomas Hellstrom } 518327c225bSThomas Hellstrom EXPORT_SYMBOL_GPL(drm_class_device_register); 519327c225bSThomas Hellstrom 520e2271704SDaniel Vetter /** 521e2271704SDaniel Vetter * drm_class_device_unregister - unregister device with the DRM sysfs class 522e2271704SDaniel Vetter * @dev: device to unregister 523e2271704SDaniel Vetter * 524e2271704SDaniel Vetter * Unregisters a &struct device from the DRM sysfs class. Essentially only used 525e2271704SDaniel Vetter * by ttm to have a place for its global settings. Drivers should never use 526e2271704SDaniel Vetter * this. 527e2271704SDaniel Vetter */ 528327c225bSThomas Hellstrom void drm_class_device_unregister(struct device *dev) 529327c225bSThomas Hellstrom { 530327c225bSThomas Hellstrom return device_unregister(dev); 531327c225bSThomas Hellstrom } 532327c225bSThomas Hellstrom EXPORT_SYMBOL_GPL(drm_class_device_unregister); 533