| Greg Kroah-Hartman | 0650fd5 | 2006-01-20 14:08:59 -0800 | [diff] [blame] | 1 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | #include <linux/device.h> | 
 | 16 | #include <linux/kdev_t.h> | 
 | 17 | #include <linux/err.h> | 
 | 18 |  | 
 | 19 | #include "drm_core.h" | 
| Dave Airlie | f210973 | 2005-09-05 21:33:44 +1000 | [diff] [blame] | 20 | #include "drmP.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 21 |  | 
| Dave Airlie | 2c14f28 | 2008-04-21 16:47:32 +1000 | [diff] [blame] | 22 | #define to_drm_minor(d) container_of(d, struct drm_minor, kdev) | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 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 | { | 
| Dave Airlie | 2c14f28 | 2008-04-21 16:47:32 +1000 | [diff] [blame] | 34 | 	struct drm_minor *drm_minor = to_drm_minor(dev); | 
 | 35 | 	struct drm_device *drm_dev = drm_minor->dev; | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 36 |  | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 37 | 	if (drm_dev->driver->suspend) | 
| Dave Airlie | b932ccb | 2008-02-20 10:02:20 +1000 | [diff] [blame] | 38 | 		return drm_dev->driver->suspend(drm_dev, state); | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 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 | { | 
| Dave Airlie | 2c14f28 | 2008-04-21 16:47:32 +1000 | [diff] [blame] | 52 | 	struct drm_minor *drm_minor = to_drm_minor(dev); | 
 | 53 | 	struct drm_device *drm_dev = drm_minor->dev; | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 54 |  | 
 | 55 | 	if (drm_dev->driver->resume) | 
 | 56 | 		return drm_dev->driver->resume(drm_dev); | 
 | 57 |  | 
 | 58 | 	return 0; | 
 | 59 | } | 
 | 60 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  * | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 75 |  * This is used to create DRM class pointer that can then be used | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  */ | 
| Greg Kroah-Hartman | 0650fd5 | 2006-01-20 14:08:59 -0800 | [diff] [blame] | 81 | struct class *drm_sysfs_create(struct module *owner, char *name) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 82 | { | 
| Greg Kroah-Hartman | 0650fd5 | 2006-01-20 14:08:59 -0800 | [diff] [blame] | 83 | 	struct class *class; | 
| Jeff Garzik | 24f73c9 | 2006-10-10 14:23:37 -0700 | [diff] [blame] | 84 | 	int err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 85 |  | 
| Greg Kroah-Hartman | 0650fd5 | 2006-01-20 14:08:59 -0800 | [diff] [blame] | 86 | 	class = class_create(owner, name); | 
| Akinobu Mita | 94f060b | 2006-12-09 10:49:47 +1100 | [diff] [blame] | 87 | 	if (IS_ERR(class)) { | 
 | 88 | 		err = PTR_ERR(class); | 
| Jeff Garzik | 24f73c9 | 2006-10-10 14:23:37 -0700 | [diff] [blame] | 89 | 		goto err_out; | 
 | 90 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 |  | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 92 | 	class->suspend = drm_sysfs_suspend; | 
 | 93 | 	class->resume = drm_sysfs_resume; | 
 | 94 |  | 
| Jeff Garzik | 24f73c9 | 2006-10-10 14:23:37 -0700 | [diff] [blame] | 95 | 	err = class_create_file(class, &class_attr_version); | 
 | 96 | 	if (err) | 
 | 97 | 		goto err_out_class; | 
 | 98 |  | 
| Greg Kroah-Hartman | 0650fd5 | 2006-01-20 14:08:59 -0800 | [diff] [blame] | 99 | 	return class; | 
| Jeff Garzik | 24f73c9 | 2006-10-10 14:23:37 -0700 | [diff] [blame] | 100 |  | 
 | 101 | err_out_class: | 
 | 102 | 	class_destroy(class); | 
 | 103 | err_out: | 
 | 104 | 	return ERR_PTR(err); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 105 | } | 
 | 106 |  | 
 | 107 | /** | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 108 |  * drm_sysfs_destroy - destroys DRM class | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 109 |  * | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 110 |  * Destroy the DRM device class. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 |  */ | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 112 | void drm_sysfs_destroy(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 113 | { | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 114 | 	if ((drm_class == NULL) || (IS_ERR(drm_class))) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 115 | 		return; | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 116 | 	class_remove_file(drm_class, &class_attr_version); | 
 | 117 | 	class_destroy(drm_class); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 118 | } | 
 | 119 |  | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 120 | static ssize_t show_dri(struct device *device, struct device_attribute *attr, | 
 | 121 | 			char *buf) | 
| Dave Airlie | 732052e | 2005-11-11 22:07:35 +1100 | [diff] [blame] | 122 | { | 
| Dave Airlie | 2c14f28 | 2008-04-21 16:47:32 +1000 | [diff] [blame] | 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); | 
| Dave Airlie | 732052e | 2005-11-11 22:07:35 +1100 | [diff] [blame] | 128 | } | 
 | 129 |  | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 130 | static struct device_attribute device_attrs[] = { | 
| Dave Airlie | 732052e | 2005-11-11 22:07:35 +1100 | [diff] [blame] | 131 | 	__ATTR(dri_library_name, S_IRUGO, show_dri, NULL), | 
 | 132 | }; | 
 | 133 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 134 | /** | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 135 |  * drm_sysfs_device_release - do nothing | 
 | 136 |  * @dev: Linux device | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 137 |  * | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 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. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 141 |  */ | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 142 | static void drm_sysfs_device_release(struct device *dev) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 | { | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 144 | 	return; | 
 | 145 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 146 |  | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 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 |  */ | 
| Dave Airlie | 2c14f28 | 2008-04-21 16:47:32 +1000 | [diff] [blame] | 156 | int drm_sysfs_device_add(struct drm_minor *minor) | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 157 | { | 
 | 158 | 	int err; | 
 | 159 | 	int i, j; | 
| Dave Airlie | 2c14f28 | 2008-04-21 16:47:32 +1000 | [diff] [blame] | 160 | 	char *minor_str; | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 161 |  | 
| Dave Airlie | 2c14f28 | 2008-04-21 16:47:32 +1000 | [diff] [blame] | 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"; | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 167 |  | 
| Dave Airlie | 2c14f28 | 2008-04-21 16:47:32 +1000 | [diff] [blame] | 168 | 	snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index); | 
 | 169 |  | 
 | 170 | 	err = device_register(&minor->kdev); | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 171 | 	if (err) { | 
 | 172 | 		DRM_ERROR("device add failed: %d\n", err); | 
| Jeff Garzik | 24f73c9 | 2006-10-10 14:23:37 -0700 | [diff] [blame] | 173 | 		goto err_out; | 
 | 174 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 175 |  | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 176 | 	for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { | 
| Dave Airlie | 2c14f28 | 2008-04-21 16:47:32 +1000 | [diff] [blame] | 177 | 		err = device_create_file(&minor->kdev, &device_attrs[i]); | 
| Jeff Garzik | 24f73c9 | 2006-10-10 14:23:37 -0700 | [diff] [blame] | 178 | 		if (err) | 
 | 179 | 			goto err_out_files; | 
 | 180 | 	} | 
 | 181 |  | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 182 | 	return 0; | 
| Jeff Garzik | 24f73c9 | 2006-10-10 14:23:37 -0700 | [diff] [blame] | 183 |  | 
 | 184 | err_out_files: | 
 | 185 | 	if (i > 0) | 
 | 186 | 		for (j = 0; j < i; j++) | 
| Dave Airlie | 2c14f28 | 2008-04-21 16:47:32 +1000 | [diff] [blame] | 187 | 			device_remove_file(&minor->kdev, &device_attrs[i]); | 
 | 188 | 	device_unregister(&minor->kdev); | 
| Jeff Garzik | 24f73c9 | 2006-10-10 14:23:37 -0700 | [diff] [blame] | 189 | err_out: | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 190 |  | 
 | 191 | 	return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 192 | } | 
 | 193 |  | 
 | 194 | /** | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 195 |  * drm_sysfs_device_remove - remove DRM device | 
 | 196 |  * @dev: DRM device to remove | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 197 |  * | 
 | 198 |  * This call unregisters and cleans up a class device that was created with a | 
 | 199 |  * call to drm_sysfs_device_add() | 
 | 200 |  */ | 
| Dave Airlie | 2c14f28 | 2008-04-21 16:47:32 +1000 | [diff] [blame] | 201 | void drm_sysfs_device_remove(struct drm_minor *minor) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 202 | { | 
| Dave Airlie | 732052e | 2005-11-11 22:07:35 +1100 | [diff] [blame] | 203 | 	int i; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 204 |  | 
| Jesse Barnes | e8b962b | 2007-11-22 14:02:38 +1000 | [diff] [blame] | 205 | 	for (i = 0; i < ARRAY_SIZE(device_attrs); i++) | 
| Dave Airlie | 2c14f28 | 2008-04-21 16:47:32 +1000 | [diff] [blame] | 206 | 		device_remove_file(&minor->kdev, &device_attrs[i]); | 
 | 207 | 	device_unregister(&minor->kdev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 208 | } |