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/err.h> 18 19 #include "drm_core.h" 20 #include "drmP.h" 21 22 #define to_drm_minor(d) container_of(d, struct drm_minor, kdev) 23 24 /** 25 * drm_sysfs_suspend - DRM class suspend hook 26 * @dev: Linux device to suspend 27 * @state: power state to enter 28 * 29 * Just figures out what the actual struct drm_device associated with 30 * @dev is and calls its suspend hook, if present. 31 */ 32 static int drm_sysfs_suspend(struct device *dev, pm_message_t state) 33 { 34 struct drm_minor *drm_minor = to_drm_minor(dev); 35 struct drm_device *drm_dev = drm_minor->dev; 36 37 if (drm_dev->driver->suspend) 38 return drm_dev->driver->suspend(drm_dev, state); 39 40 return 0; 41 } 42 43 /** 44 * drm_sysfs_resume - DRM class resume hook 45 * @dev: Linux device to resume 46 * 47 * Just figures out what the actual struct drm_device associated with 48 * @dev is and calls its resume hook, if present. 49 */ 50 static int drm_sysfs_resume(struct device *dev) 51 { 52 struct drm_minor *drm_minor = to_drm_minor(dev); 53 struct drm_device *drm_dev = drm_minor->dev; 54 55 if (drm_dev->driver->resume) 56 return drm_dev->driver->resume(drm_dev); 57 58 return 0; 59 } 60 61 /* Display the version of drm_core. This doesn't work right in current design */ 62 static ssize_t version_show(struct class *dev, char *buf) 63 { 64 return sprintf(buf, "%s %d.%d.%d %s\n", CORE_NAME, CORE_MAJOR, 65 CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); 66 } 67 68 static CLASS_ATTR(version, S_IRUGO, version_show, NULL); 69 70 /** 71 * drm_sysfs_create - create a struct drm_sysfs_class structure 72 * @owner: pointer to the module that is to "own" this struct drm_sysfs_class 73 * @name: pointer to a string for the name of this class. 74 * 75 * This is used to create DRM class pointer that can then be used 76 * in calls to drm_sysfs_device_add(). 77 * 78 * Note, the pointer created here is to be destroyed when finished by making a 79 * call to drm_sysfs_destroy(). 80 */ 81 struct class *drm_sysfs_create(struct module *owner, char *name) 82 { 83 struct class *class; 84 int err; 85 86 class = class_create(owner, name); 87 if (IS_ERR(class)) { 88 err = PTR_ERR(class); 89 goto err_out; 90 } 91 92 class->suspend = drm_sysfs_suspend; 93 class->resume = drm_sysfs_resume; 94 95 err = class_create_file(class, &class_attr_version); 96 if (err) 97 goto err_out_class; 98 99 return class; 100 101 err_out_class: 102 class_destroy(class); 103 err_out: 104 return ERR_PTR(err); 105 } 106 107 /** 108 * drm_sysfs_destroy - destroys DRM class 109 * 110 * Destroy the DRM device class. 111 */ 112 void drm_sysfs_destroy(void) 113 { 114 if ((drm_class == NULL) || (IS_ERR(drm_class))) 115 return; 116 class_remove_file(drm_class, &class_attr_version); 117 class_destroy(drm_class); 118 } 119 120 static ssize_t show_dri(struct device *device, struct device_attribute *attr, 121 char *buf) 122 { 123 struct drm_minor *drm_minor = to_drm_minor(device); 124 struct drm_device *drm_dev = drm_minor->dev; 125 if (drm_dev->driver->dri_library_name) 126 return drm_dev->driver->dri_library_name(drm_dev, buf); 127 return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name); 128 } 129 130 static struct device_attribute device_attrs[] = { 131 __ATTR(dri_library_name, S_IRUGO, show_dri, NULL), 132 }; 133 134 /** 135 * drm_sysfs_device_release - do nothing 136 * @dev: Linux device 137 * 138 * Normally, this would free the DRM device associated with @dev, along 139 * with cleaning up any other stuff. But we do that in the DRM core, so 140 * this function can just return and hope that the core does its job. 141 */ 142 static void drm_sysfs_device_release(struct device *dev) 143 { 144 return; 145 } 146 147 /** 148 * drm_sysfs_device_add - adds a class device to sysfs for a character driver 149 * @dev: DRM device to be added 150 * @head: DRM head in question 151 * 152 * Add a DRM device to the DRM's device model class. We use @dev's PCI device 153 * as the parent for the Linux device, and make sure it has a file containing 154 * the driver we're using (for userspace compatibility). 155 */ 156 int drm_sysfs_device_add(struct drm_minor *minor) 157 { 158 int err; 159 int i, j; 160 char *minor_str; 161 162 minor->kdev.parent = &minor->dev->pdev->dev; 163 minor->kdev.class = drm_class; 164 minor->kdev.release = drm_sysfs_device_release; 165 minor->kdev.devt = minor->device; 166 minor_str = "card%d"; 167 168 snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index); 169 170 err = device_register(&minor->kdev); 171 if (err) { 172 DRM_ERROR("device add failed: %d\n", err); 173 goto err_out; 174 } 175 176 for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { 177 err = device_create_file(&minor->kdev, &device_attrs[i]); 178 if (err) 179 goto err_out_files; 180 } 181 182 return 0; 183 184 err_out_files: 185 if (i > 0) 186 for (j = 0; j < i; j++) 187 device_remove_file(&minor->kdev, &device_attrs[i]); 188 device_unregister(&minor->kdev); 189 err_out: 190 191 return err; 192 } 193 194 /** 195 * drm_sysfs_device_remove - remove DRM device 196 * @dev: DRM device to remove 197 * 198 * This call unregisters and cleans up a class device that was created with a 199 * call to drm_sysfs_device_add() 200 */ 201 void drm_sysfs_device_remove(struct drm_minor *minor) 202 { 203 int i; 204 205 for (i = 0; i < ARRAY_SIZE(device_attrs); i++) 206 device_remove_file(&minor->kdev, &device_attrs[i]); 207 device_unregister(&minor->kdev); 208 } 209