1 2 /* 3 * drm_sysfs.c - Modifications to drm_sysfs_class.c to support 4 * extra sysfs attribute from DRM. Normal drm_sysfs_class 5 * does not allow adding attributes. 6 * 7 * Copyright (c) 2004 Jon Smirl <jonsmirl@gmail.com> 8 * Copyright (c) 2003-2004 Greg Kroah-Hartman <greg@kroah.com> 9 * Copyright (c) 2003-2004 IBM Corp. 10 * 11 * This file is released under the GPLv2 12 * 13 */ 14 15 #include <linux/device.h> 16 #include <linux/kdev_t.h> 17 #include <linux/gfp.h> 18 #include <linux/err.h> 19 #include <linux/export.h> 20 21 #include <drm/drm_sysfs.h> 22 #include <drm/drm_core.h> 23 #include <drm/drmP.h> 24 #include "drm_internal.h" 25 26 #define to_drm_minor(d) dev_get_drvdata(d) 27 #define to_drm_connector(d) dev_get_drvdata(d) 28 29 static struct device_type drm_sysfs_device_minor = { 30 .name = "drm_minor" 31 }; 32 33 struct class *drm_class; 34 35 static char *drm_devnode(struct device *dev, umode_t *mode) 36 { 37 return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); 38 } 39 40 static CLASS_ATTR_STRING(version, S_IRUGO, 41 CORE_NAME " " 42 __stringify(CORE_MAJOR) "." 43 __stringify(CORE_MINOR) "." 44 __stringify(CORE_PATCHLEVEL) " " 45 CORE_DATE); 46 47 /** 48 * drm_sysfs_init - initialize sysfs helpers 49 * 50 * This is used to create the DRM class, which is the implicit parent of any 51 * other top-level DRM sysfs objects. 52 * 53 * You must call drm_sysfs_destroy() to release the allocated resources. 54 * 55 * Return: 0 on success, negative error code on failure. 56 */ 57 int drm_sysfs_init(void) 58 { 59 int err; 60 61 drm_class = class_create(THIS_MODULE, "drm"); 62 if (IS_ERR(drm_class)) 63 return PTR_ERR(drm_class); 64 65 err = class_create_file(drm_class, &class_attr_version.attr); 66 if (err) { 67 class_destroy(drm_class); 68 drm_class = NULL; 69 return err; 70 } 71 72 drm_class->devnode = drm_devnode; 73 return 0; 74 } 75 76 /** 77 * drm_sysfs_destroy - destroys DRM class 78 * 79 * Destroy the DRM device class. 80 */ 81 void drm_sysfs_destroy(void) 82 { 83 if (IS_ERR_OR_NULL(drm_class)) 84 return; 85 class_remove_file(drm_class, &class_attr_version.attr); 86 class_destroy(drm_class); 87 drm_class = NULL; 88 } 89 90 /* 91 * Connector properties 92 */ 93 static ssize_t status_store(struct device *device, 94 struct device_attribute *attr, 95 const char *buf, size_t count) 96 { 97 struct drm_connector *connector = to_drm_connector(device); 98 struct drm_device *dev = connector->dev; 99 enum drm_connector_force old_force; 100 int ret; 101 102 ret = mutex_lock_interruptible(&dev->mode_config.mutex); 103 if (ret) 104 return ret; 105 106 old_force = connector->force; 107 108 if (sysfs_streq(buf, "detect")) 109 connector->force = 0; 110 else if (sysfs_streq(buf, "on")) 111 connector->force = DRM_FORCE_ON; 112 else if (sysfs_streq(buf, "on-digital")) 113 connector->force = DRM_FORCE_ON_DIGITAL; 114 else if (sysfs_streq(buf, "off")) 115 connector->force = DRM_FORCE_OFF; 116 else 117 ret = -EINVAL; 118 119 if (old_force != connector->force || !connector->force) { 120 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force updated from %d to %d or reprobing\n", 121 connector->base.id, 122 connector->name, 123 old_force, connector->force); 124 125 connector->funcs->fill_modes(connector, 126 dev->mode_config.max_width, 127 dev->mode_config.max_height); 128 } 129 130 mutex_unlock(&dev->mode_config.mutex); 131 132 return ret ? ret : count; 133 } 134 135 static ssize_t status_show(struct device *device, 136 struct device_attribute *attr, 137 char *buf) 138 { 139 struct drm_connector *connector = to_drm_connector(device); 140 enum drm_connector_status status; 141 142 status = READ_ONCE(connector->status); 143 144 return snprintf(buf, PAGE_SIZE, "%s\n", 145 drm_get_connector_status_name(status)); 146 } 147 148 static ssize_t dpms_show(struct device *device, 149 struct device_attribute *attr, 150 char *buf) 151 { 152 struct drm_connector *connector = to_drm_connector(device); 153 int dpms; 154 155 dpms = READ_ONCE(connector->dpms); 156 157 return snprintf(buf, PAGE_SIZE, "%s\n", 158 drm_get_dpms_name(dpms)); 159 } 160 161 static ssize_t enabled_show(struct device *device, 162 struct device_attribute *attr, 163 char *buf) 164 { 165 struct drm_connector *connector = to_drm_connector(device); 166 bool enabled; 167 168 enabled = READ_ONCE(connector->encoder); 169 170 return snprintf(buf, PAGE_SIZE, enabled ? "enabled\n" : "disabled\n"); 171 } 172 173 static ssize_t edid_show(struct file *filp, struct kobject *kobj, 174 struct bin_attribute *attr, char *buf, loff_t off, 175 size_t count) 176 { 177 struct device *connector_dev = kobj_to_dev(kobj); 178 struct drm_connector *connector = to_drm_connector(connector_dev); 179 unsigned char *edid; 180 size_t size; 181 ssize_t ret = 0; 182 183 mutex_lock(&connector->dev->mode_config.mutex); 184 if (!connector->edid_blob_ptr) 185 goto unlock; 186 187 edid = connector->edid_blob_ptr->data; 188 size = connector->edid_blob_ptr->length; 189 if (!edid) 190 goto unlock; 191 192 if (off >= size) 193 goto unlock; 194 195 if (off + count > size) 196 count = size - off; 197 memcpy(buf, edid + off, count); 198 199 ret = count; 200 unlock: 201 mutex_unlock(&connector->dev->mode_config.mutex); 202 203 return ret; 204 } 205 206 static ssize_t modes_show(struct device *device, 207 struct device_attribute *attr, 208 char *buf) 209 { 210 struct drm_connector *connector = to_drm_connector(device); 211 struct drm_display_mode *mode; 212 int written = 0; 213 214 mutex_lock(&connector->dev->mode_config.mutex); 215 list_for_each_entry(mode, &connector->modes, head) { 216 written += snprintf(buf + written, PAGE_SIZE - written, "%s\n", 217 mode->name); 218 } 219 mutex_unlock(&connector->dev->mode_config.mutex); 220 221 return written; 222 } 223 224 static DEVICE_ATTR_RW(status); 225 static DEVICE_ATTR_RO(enabled); 226 static DEVICE_ATTR_RO(dpms); 227 static DEVICE_ATTR_RO(modes); 228 229 static struct attribute *connector_dev_attrs[] = { 230 &dev_attr_status.attr, 231 &dev_attr_enabled.attr, 232 &dev_attr_dpms.attr, 233 &dev_attr_modes.attr, 234 NULL 235 }; 236 237 static struct bin_attribute edid_attr = { 238 .attr.name = "edid", 239 .attr.mode = 0444, 240 .size = 0, 241 .read = edid_show, 242 }; 243 244 static struct bin_attribute *connector_bin_attrs[] = { 245 &edid_attr, 246 NULL 247 }; 248 249 static const struct attribute_group connector_dev_group = { 250 .attrs = connector_dev_attrs, 251 .bin_attrs = connector_bin_attrs, 252 }; 253 254 static const struct attribute_group *connector_dev_groups[] = { 255 &connector_dev_group, 256 NULL 257 }; 258 259 /** 260 * drm_sysfs_connector_add - add a connector to sysfs 261 * @connector: connector to add 262 * 263 * Create a connector device in sysfs, along with its associated connector 264 * properties (so far, connection status, dpms, mode list & edid) and 265 * generate a hotplug event so userspace knows there's a new connector 266 * available. 267 */ 268 int drm_sysfs_connector_add(struct drm_connector *connector) 269 { 270 struct drm_device *dev = connector->dev; 271 272 if (connector->kdev) 273 return 0; 274 275 connector->kdev = 276 device_create_with_groups(drm_class, dev->primary->kdev, 0, 277 connector, connector_dev_groups, 278 "card%d-%s", dev->primary->index, 279 connector->name); 280 DRM_DEBUG("adding \"%s\" to sysfs\n", 281 connector->name); 282 283 if (IS_ERR(connector->kdev)) { 284 DRM_ERROR("failed to register connector device: %ld\n", PTR_ERR(connector->kdev)); 285 return PTR_ERR(connector->kdev); 286 } 287 288 /* Let userspace know we have a new connector */ 289 drm_sysfs_hotplug_event(dev); 290 291 return 0; 292 } 293 294 /** 295 * drm_sysfs_connector_remove - remove an connector device from sysfs 296 * @connector: connector to remove 297 * 298 * Remove @connector and its associated attributes from sysfs. Note that 299 * the device model core will take care of sending the "remove" uevent 300 * at this time, so we don't need to do it. 301 * 302 * Note: 303 * This routine should only be called if the connector was previously 304 * successfully registered. If @connector hasn't been registered yet, 305 * you'll likely see a panic somewhere deep in sysfs code when called. 306 */ 307 void drm_sysfs_connector_remove(struct drm_connector *connector) 308 { 309 if (!connector->kdev) 310 return; 311 DRM_DEBUG("removing \"%s\" from sysfs\n", 312 connector->name); 313 314 device_unregister(connector->kdev); 315 connector->kdev = NULL; 316 } 317 318 /** 319 * drm_sysfs_hotplug_event - generate a DRM uevent 320 * @dev: DRM device 321 * 322 * Send a uevent for the DRM device specified by @dev. Currently we only 323 * set HOTPLUG=1 in the uevent environment, but this could be expanded to 324 * deal with other types of events. 325 */ 326 void drm_sysfs_hotplug_event(struct drm_device *dev) 327 { 328 char *event_string = "HOTPLUG=1"; 329 char *envp[] = { event_string, NULL }; 330 331 DRM_DEBUG("generating hotplug event\n"); 332 333 kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp); 334 } 335 EXPORT_SYMBOL(drm_sysfs_hotplug_event); 336 337 static void drm_sysfs_release(struct device *dev) 338 { 339 kfree(dev); 340 } 341 342 /** 343 * drm_sysfs_minor_alloc() - Allocate sysfs device for given minor 344 * @minor: minor to allocate sysfs device for 345 * 346 * This allocates a new sysfs device for @minor and returns it. The device is 347 * not registered nor linked. The caller has to use device_add() and 348 * device_del() to register and unregister it. 349 * 350 * Note that dev_get_drvdata() on the new device will return the minor. 351 * However, the device does not hold a ref-count to the minor nor to the 352 * underlying drm_device. This is unproblematic as long as you access the 353 * private data only in sysfs callbacks. device_del() disables those 354 * synchronously, so they cannot be called after you cleanup a minor. 355 */ 356 struct device *drm_sysfs_minor_alloc(struct drm_minor *minor) 357 { 358 const char *minor_str; 359 struct device *kdev; 360 int r; 361 362 if (minor->type == DRM_MINOR_CONTROL) 363 minor_str = "controlD%d"; 364 else if (minor->type == DRM_MINOR_RENDER) 365 minor_str = "renderD%d"; 366 else 367 minor_str = "card%d"; 368 369 kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); 370 if (!kdev) 371 return ERR_PTR(-ENOMEM); 372 373 device_initialize(kdev); 374 kdev->devt = MKDEV(DRM_MAJOR, minor->index); 375 kdev->class = drm_class; 376 kdev->type = &drm_sysfs_device_minor; 377 kdev->parent = minor->dev->dev; 378 kdev->release = drm_sysfs_release; 379 dev_set_drvdata(kdev, minor); 380 381 r = dev_set_name(kdev, minor_str, minor->index); 382 if (r < 0) 383 goto err_free; 384 385 return kdev; 386 387 err_free: 388 put_device(kdev); 389 return ERR_PTR(r); 390 } 391 392 /** 393 * drm_class_device_register - Register a struct device in the drm class. 394 * 395 * @dev: pointer to struct device to register. 396 * 397 * @dev should have all relevant members pre-filled with the exception 398 * of the class member. In particular, the device_type member must 399 * be set. 400 */ 401 402 int drm_class_device_register(struct device *dev) 403 { 404 if (!drm_class || IS_ERR(drm_class)) 405 return -ENOENT; 406 407 dev->class = drm_class; 408 return device_register(dev); 409 } 410 EXPORT_SYMBOL_GPL(drm_class_device_register); 411 412 void drm_class_device_unregister(struct device *dev) 413 { 414 return device_unregister(dev); 415 } 416 EXPORT_SYMBOL_GPL(drm_class_device_unregister); 417