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 25 #define to_drm_minor(d) container_of(d, struct drm_minor, kdev) 26 #define to_drm_connector(d) container_of(d, struct drm_connector, kdev) 27 28 static struct device_type drm_sysfs_device_minor = { 29 .name = "drm_minor" 30 }; 31 32 /** 33 * drm_class_suspend - DRM class suspend hook 34 * @dev: Linux device to suspend 35 * @state: power state to enter 36 * 37 * Just figures out what the actual struct drm_device associated with 38 * @dev is and calls its suspend hook, if present. 39 */ 40 static int drm_class_suspend(struct device *dev, pm_message_t state) 41 { 42 if (dev->type == &drm_sysfs_device_minor) { 43 struct drm_minor *drm_minor = to_drm_minor(dev); 44 struct drm_device *drm_dev = drm_minor->dev; 45 46 if (drm_minor->type == DRM_MINOR_LEGACY && 47 !drm_core_check_feature(drm_dev, DRIVER_MODESET) && 48 drm_dev->driver->suspend) 49 return drm_dev->driver->suspend(drm_dev, state); 50 } 51 return 0; 52 } 53 54 /** 55 * drm_class_resume - DRM class resume hook 56 * @dev: Linux device to resume 57 * 58 * Just figures out what the actual struct drm_device associated with 59 * @dev is and calls its resume hook, if present. 60 */ 61 static int drm_class_resume(struct device *dev) 62 { 63 if (dev->type == &drm_sysfs_device_minor) { 64 struct drm_minor *drm_minor = to_drm_minor(dev); 65 struct drm_device *drm_dev = drm_minor->dev; 66 67 if (drm_minor->type == DRM_MINOR_LEGACY && 68 !drm_core_check_feature(drm_dev, DRIVER_MODESET) && 69 drm_dev->driver->resume) 70 return drm_dev->driver->resume(drm_dev); 71 } 72 return 0; 73 } 74 75 static char *drm_devnode(struct device *dev, umode_t *mode) 76 { 77 return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); 78 } 79 80 static CLASS_ATTR_STRING(version, S_IRUGO, 81 CORE_NAME " " 82 __stringify(CORE_MAJOR) "." 83 __stringify(CORE_MINOR) "." 84 __stringify(CORE_PATCHLEVEL) " " 85 CORE_DATE); 86 87 /** 88 * drm_sysfs_create - create a struct drm_sysfs_class structure 89 * @owner: pointer to the module that is to "own" this struct drm_sysfs_class 90 * @name: pointer to a string for the name of this class. 91 * 92 * This is used to create DRM class pointer that can then be used 93 * in calls to drm_sysfs_device_add(). 94 * 95 * Note, the pointer created here is to be destroyed when finished by making a 96 * call to drm_sysfs_destroy(). 97 */ 98 struct class *drm_sysfs_create(struct module *owner, char *name) 99 { 100 struct class *class; 101 int err; 102 103 class = class_create(owner, name); 104 if (IS_ERR(class)) { 105 err = PTR_ERR(class); 106 goto err_out; 107 } 108 109 class->suspend = drm_class_suspend; 110 class->resume = drm_class_resume; 111 112 err = class_create_file(class, &class_attr_version.attr); 113 if (err) 114 goto err_out_class; 115 116 class->devnode = drm_devnode; 117 118 return class; 119 120 err_out_class: 121 class_destroy(class); 122 err_out: 123 return ERR_PTR(err); 124 } 125 126 /** 127 * drm_sysfs_destroy - destroys DRM class 128 * 129 * Destroy the DRM device class. 130 */ 131 void drm_sysfs_destroy(void) 132 { 133 if ((drm_class == NULL) || (IS_ERR(drm_class))) 134 return; 135 class_remove_file(drm_class, &class_attr_version.attr); 136 class_destroy(drm_class); 137 drm_class = NULL; 138 } 139 140 /** 141 * drm_sysfs_device_release - do nothing 142 * @dev: Linux device 143 * 144 * Normally, this would free the DRM device associated with @dev, along 145 * with cleaning up any other stuff. But we do that in the DRM core, so 146 * this function can just return and hope that the core does its job. 147 */ 148 static void drm_sysfs_device_release(struct device *dev) 149 { 150 memset(dev, 0, sizeof(struct device)); 151 return; 152 } 153 154 /* 155 * Connector properties 156 */ 157 static ssize_t status_show(struct device *device, 158 struct device_attribute *attr, 159 char *buf) 160 { 161 struct drm_connector *connector = to_drm_connector(device); 162 enum drm_connector_status status; 163 int ret; 164 165 ret = mutex_lock_interruptible(&connector->dev->mode_config.mutex); 166 if (ret) 167 return ret; 168 169 status = connector->funcs->detect(connector, true); 170 mutex_unlock(&connector->dev->mode_config.mutex); 171 172 return snprintf(buf, PAGE_SIZE, "%s\n", 173 drm_get_connector_status_name(status)); 174 } 175 176 static ssize_t dpms_show(struct device *device, 177 struct device_attribute *attr, 178 char *buf) 179 { 180 struct drm_connector *connector = to_drm_connector(device); 181 struct drm_device *dev = connector->dev; 182 uint64_t dpms_status; 183 int ret; 184 185 ret = drm_connector_property_get_value(connector, 186 dev->mode_config.dpms_property, 187 &dpms_status); 188 if (ret) 189 return 0; 190 191 return snprintf(buf, PAGE_SIZE, "%s\n", 192 drm_get_dpms_name((int)dpms_status)); 193 } 194 195 static ssize_t enabled_show(struct device *device, 196 struct device_attribute *attr, 197 char *buf) 198 { 199 struct drm_connector *connector = to_drm_connector(device); 200 201 return snprintf(buf, PAGE_SIZE, "%s\n", connector->encoder ? "enabled" : 202 "disabled"); 203 } 204 205 static ssize_t edid_show(struct file *filp, struct kobject *kobj, 206 struct bin_attribute *attr, char *buf, loff_t off, 207 size_t count) 208 { 209 struct device *connector_dev = container_of(kobj, struct device, kobj); 210 struct drm_connector *connector = to_drm_connector(connector_dev); 211 unsigned char *edid; 212 size_t size; 213 214 if (!connector->edid_blob_ptr) 215 return 0; 216 217 edid = connector->edid_blob_ptr->data; 218 size = connector->edid_blob_ptr->length; 219 if (!edid) 220 return 0; 221 222 if (off >= size) 223 return 0; 224 225 if (off + count > size) 226 count = size - off; 227 memcpy(buf, edid + off, count); 228 229 return count; 230 } 231 232 static ssize_t modes_show(struct device *device, 233 struct device_attribute *attr, 234 char *buf) 235 { 236 struct drm_connector *connector = to_drm_connector(device); 237 struct drm_display_mode *mode; 238 int written = 0; 239 240 list_for_each_entry(mode, &connector->modes, head) { 241 written += snprintf(buf + written, PAGE_SIZE - written, "%s\n", 242 mode->name); 243 } 244 245 return written; 246 } 247 248 static ssize_t subconnector_show(struct device *device, 249 struct device_attribute *attr, 250 char *buf) 251 { 252 struct drm_connector *connector = to_drm_connector(device); 253 struct drm_device *dev = connector->dev; 254 struct drm_property *prop = NULL; 255 uint64_t subconnector; 256 int is_tv = 0; 257 int ret; 258 259 switch (connector->connector_type) { 260 case DRM_MODE_CONNECTOR_DVII: 261 prop = dev->mode_config.dvi_i_subconnector_property; 262 break; 263 case DRM_MODE_CONNECTOR_Composite: 264 case DRM_MODE_CONNECTOR_SVIDEO: 265 case DRM_MODE_CONNECTOR_Component: 266 case DRM_MODE_CONNECTOR_TV: 267 prop = dev->mode_config.tv_subconnector_property; 268 is_tv = 1; 269 break; 270 default: 271 DRM_ERROR("Wrong connector type for this property\n"); 272 return 0; 273 } 274 275 if (!prop) { 276 DRM_ERROR("Unable to find subconnector property\n"); 277 return 0; 278 } 279 280 ret = drm_connector_property_get_value(connector, prop, &subconnector); 281 if (ret) 282 return 0; 283 284 return snprintf(buf, PAGE_SIZE, "%s", is_tv ? 285 drm_get_tv_subconnector_name((int)subconnector) : 286 drm_get_dvi_i_subconnector_name((int)subconnector)); 287 } 288 289 static ssize_t select_subconnector_show(struct device *device, 290 struct device_attribute *attr, 291 char *buf) 292 { 293 struct drm_connector *connector = to_drm_connector(device); 294 struct drm_device *dev = connector->dev; 295 struct drm_property *prop = NULL; 296 uint64_t subconnector; 297 int is_tv = 0; 298 int ret; 299 300 switch (connector->connector_type) { 301 case DRM_MODE_CONNECTOR_DVII: 302 prop = dev->mode_config.dvi_i_select_subconnector_property; 303 break; 304 case DRM_MODE_CONNECTOR_Composite: 305 case DRM_MODE_CONNECTOR_SVIDEO: 306 case DRM_MODE_CONNECTOR_Component: 307 case DRM_MODE_CONNECTOR_TV: 308 prop = dev->mode_config.tv_select_subconnector_property; 309 is_tv = 1; 310 break; 311 default: 312 DRM_ERROR("Wrong connector type for this property\n"); 313 return 0; 314 } 315 316 if (!prop) { 317 DRM_ERROR("Unable to find select subconnector property\n"); 318 return 0; 319 } 320 321 ret = drm_connector_property_get_value(connector, prop, &subconnector); 322 if (ret) 323 return 0; 324 325 return snprintf(buf, PAGE_SIZE, "%s", is_tv ? 326 drm_get_tv_select_name((int)subconnector) : 327 drm_get_dvi_i_select_name((int)subconnector)); 328 } 329 330 static struct device_attribute connector_attrs[] = { 331 __ATTR_RO(status), 332 __ATTR_RO(enabled), 333 __ATTR_RO(dpms), 334 __ATTR_RO(modes), 335 }; 336 337 /* These attributes are for both DVI-I connectors and all types of tv-out. */ 338 static struct device_attribute connector_attrs_opt1[] = { 339 __ATTR_RO(subconnector), 340 __ATTR_RO(select_subconnector), 341 }; 342 343 static struct bin_attribute edid_attr = { 344 .attr.name = "edid", 345 .attr.mode = 0444, 346 .size = 0, 347 .read = edid_show, 348 }; 349 350 /** 351 * drm_sysfs_connector_add - add a connector to sysfs 352 * @connector: connector to add 353 * 354 * Create a connector device in sysfs, along with its associated connector 355 * properties (so far, connection status, dpms, mode list & edid) and 356 * generate a hotplug event so userspace knows there's a new connector 357 * available. 358 * 359 * Note: 360 * This routine should only be called *once* for each registered connector. 361 * A second call for an already registered connector will trigger the BUG_ON 362 * below. 363 */ 364 int drm_sysfs_connector_add(struct drm_connector *connector) 365 { 366 struct drm_device *dev = connector->dev; 367 int attr_cnt = 0; 368 int opt_cnt = 0; 369 int i; 370 int ret; 371 372 /* We shouldn't get called more than once for the same connector */ 373 BUG_ON(device_is_registered(&connector->kdev)); 374 375 connector->kdev.parent = &dev->primary->kdev; 376 connector->kdev.class = drm_class; 377 connector->kdev.release = drm_sysfs_device_release; 378 379 DRM_DEBUG("adding \"%s\" to sysfs\n", 380 drm_get_connector_name(connector)); 381 382 dev_set_name(&connector->kdev, "card%d-%s", 383 dev->primary->index, drm_get_connector_name(connector)); 384 ret = device_register(&connector->kdev); 385 386 if (ret) { 387 DRM_ERROR("failed to register connector device: %d\n", ret); 388 goto out; 389 } 390 391 /* Standard attributes */ 392 393 for (attr_cnt = 0; attr_cnt < ARRAY_SIZE(connector_attrs); attr_cnt++) { 394 ret = device_create_file(&connector->kdev, &connector_attrs[attr_cnt]); 395 if (ret) 396 goto err_out_files; 397 } 398 399 /* Optional attributes */ 400 /* 401 * In the long run it maybe a good idea to make one set of 402 * optionals per connector type. 403 */ 404 switch (connector->connector_type) { 405 case DRM_MODE_CONNECTOR_DVII: 406 case DRM_MODE_CONNECTOR_Composite: 407 case DRM_MODE_CONNECTOR_SVIDEO: 408 case DRM_MODE_CONNECTOR_Component: 409 case DRM_MODE_CONNECTOR_TV: 410 for (opt_cnt = 0; opt_cnt < ARRAY_SIZE(connector_attrs_opt1); opt_cnt++) { 411 ret = device_create_file(&connector->kdev, &connector_attrs_opt1[opt_cnt]); 412 if (ret) 413 goto err_out_files; 414 } 415 break; 416 default: 417 break; 418 } 419 420 ret = sysfs_create_bin_file(&connector->kdev.kobj, &edid_attr); 421 if (ret) 422 goto err_out_files; 423 424 /* Let userspace know we have a new connector */ 425 drm_sysfs_hotplug_event(dev); 426 427 return 0; 428 429 err_out_files: 430 for (i = 0; i < opt_cnt; i++) 431 device_remove_file(&connector->kdev, &connector_attrs_opt1[i]); 432 for (i = 0; i < attr_cnt; i++) 433 device_remove_file(&connector->kdev, &connector_attrs[i]); 434 device_unregister(&connector->kdev); 435 436 out: 437 return ret; 438 } 439 EXPORT_SYMBOL(drm_sysfs_connector_add); 440 441 /** 442 * drm_sysfs_connector_remove - remove an connector device from sysfs 443 * @connector: connector to remove 444 * 445 * Remove @connector and its associated attributes from sysfs. Note that 446 * the device model core will take care of sending the "remove" uevent 447 * at this time, so we don't need to do it. 448 * 449 * Note: 450 * This routine should only be called if the connector was previously 451 * successfully registered. If @connector hasn't been registered yet, 452 * you'll likely see a panic somewhere deep in sysfs code when called. 453 */ 454 void drm_sysfs_connector_remove(struct drm_connector *connector) 455 { 456 int i; 457 458 if (!connector->kdev.parent) 459 return; 460 DRM_DEBUG("removing \"%s\" from sysfs\n", 461 drm_get_connector_name(connector)); 462 463 for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) 464 device_remove_file(&connector->kdev, &connector_attrs[i]); 465 sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr); 466 device_unregister(&connector->kdev); 467 connector->kdev.parent = NULL; 468 } 469 EXPORT_SYMBOL(drm_sysfs_connector_remove); 470 471 /** 472 * drm_sysfs_hotplug_event - generate a DRM uevent 473 * @dev: DRM device 474 * 475 * Send a uevent for the DRM device specified by @dev. Currently we only 476 * set HOTPLUG=1 in the uevent environment, but this could be expanded to 477 * deal with other types of events. 478 */ 479 void drm_sysfs_hotplug_event(struct drm_device *dev) 480 { 481 char *event_string = "HOTPLUG=1"; 482 char *envp[] = { event_string, NULL }; 483 484 DRM_DEBUG("generating hotplug event\n"); 485 486 kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); 487 } 488 EXPORT_SYMBOL(drm_sysfs_hotplug_event); 489 490 /** 491 * drm_sysfs_device_add - adds a class device to sysfs for a character driver 492 * @dev: DRM device to be added 493 * @head: DRM head in question 494 * 495 * Add a DRM device to the DRM's device model class. We use @dev's PCI device 496 * as the parent for the Linux device, and make sure it has a file containing 497 * the driver we're using (for userspace compatibility). 498 */ 499 int drm_sysfs_device_add(struct drm_minor *minor) 500 { 501 int err; 502 char *minor_str; 503 504 minor->kdev.parent = minor->dev->dev; 505 506 minor->kdev.class = drm_class; 507 minor->kdev.release = drm_sysfs_device_release; 508 minor->kdev.devt = minor->device; 509 minor->kdev.type = &drm_sysfs_device_minor; 510 if (minor->type == DRM_MINOR_CONTROL) 511 minor_str = "controlD%d"; 512 else if (minor->type == DRM_MINOR_RENDER) 513 minor_str = "renderD%d"; 514 else 515 minor_str = "card%d"; 516 517 dev_set_name(&minor->kdev, minor_str, minor->index); 518 519 err = device_register(&minor->kdev); 520 if (err) { 521 DRM_ERROR("device add failed: %d\n", err); 522 goto err_out; 523 } 524 525 return 0; 526 527 err_out: 528 return err; 529 } 530 531 /** 532 * drm_sysfs_device_remove - remove DRM device 533 * @dev: DRM device to remove 534 * 535 * This call unregisters and cleans up a class device that was created with a 536 * call to drm_sysfs_device_add() 537 */ 538 void drm_sysfs_device_remove(struct drm_minor *minor) 539 { 540 if (minor->kdev.parent) 541 device_unregister(&minor->kdev); 542 minor->kdev.parent = NULL; 543 } 544 545 546 /** 547 * drm_class_device_register - Register a struct device in the drm class. 548 * 549 * @dev: pointer to struct device to register. 550 * 551 * @dev should have all relevant members pre-filled with the exception 552 * of the class member. In particular, the device_type member must 553 * be set. 554 */ 555 556 int drm_class_device_register(struct device *dev) 557 { 558 if (!drm_class || IS_ERR(drm_class)) 559 return -ENOENT; 560 561 dev->class = drm_class; 562 return device_register(dev); 563 } 564 EXPORT_SYMBOL_GPL(drm_class_device_register); 565 566 void drm_class_device_unregister(struct device *dev) 567 { 568 return device_unregister(dev); 569 } 570 EXPORT_SYMBOL_GPL(drm_class_device_unregister); 571