Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6] / drivers / gpu / drm / drm_sysfs.c
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[j]);
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 }