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