Merge branch 'pending' of master.kernel.org:/pub/scm/linux/kernel/git/vxy/lksctp-dev
[linux-2.6] / drivers / char / 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_device(d) container_of(d, struct drm_device, dev)
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_device *drm_dev = to_drm_device(dev);
35
36         printk(KERN_ERR "%s\n", __FUNCTION__);
37
38         if (drm_dev->driver->suspend)
39                 return drm_dev->driver->suspend(drm_dev);
40
41         return 0;
42 }
43
44 /**
45  * drm_sysfs_resume - DRM class resume hook
46  * @dev: Linux device to resume
47  *
48  * Just figures out what the actual struct drm_device associated with
49  * @dev is and calls its resume hook, if present.
50  */
51 static int drm_sysfs_resume(struct device *dev)
52 {
53         struct drm_device *drm_dev = to_drm_device(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_device *dev = to_drm_device(device);
124         if (dev->driver->dri_library_name)
125                 return dev->driver->dri_library_name(dev, buf);
126         return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name);
127 }
128
129 static struct device_attribute device_attrs[] = {
130         __ATTR(dri_library_name, S_IRUGO, show_dri, NULL),
131 };
132
133 /**
134  * drm_sysfs_device_release - do nothing
135  * @dev: Linux device
136  *
137  * Normally, this would free the DRM device associated with @dev, along
138  * with cleaning up any other stuff.  But we do that in the DRM core, so
139  * this function can just return and hope that the core does its job.
140  */
141 static void drm_sysfs_device_release(struct device *dev)
142 {
143         return;
144 }
145
146 /**
147  * drm_sysfs_device_add - adds a class device to sysfs for a character driver
148  * @dev: DRM device to be added
149  * @head: DRM head in question
150  *
151  * Add a DRM device to the DRM's device model class.  We use @dev's PCI device
152  * as the parent for the Linux device, and make sure it has a file containing
153  * the driver we're using (for userspace compatibility).
154  */
155 int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head)
156 {
157         int err;
158         int i, j;
159
160         dev->dev.parent = &dev->pdev->dev;
161         dev->dev.class = drm_class;
162         dev->dev.release = drm_sysfs_device_release;
163         dev->dev.devt = head->device;
164         snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", head->minor);
165
166         err = device_register(&dev->dev);
167         if (err) {
168                 DRM_ERROR("device add failed: %d\n", err);
169                 goto err_out;
170         }
171
172         for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
173                 err = device_create_file(&dev->dev, &device_attrs[i]);
174                 if (err)
175                         goto err_out_files;
176         }
177
178         return 0;
179
180 err_out_files:
181         if (i > 0)
182                 for (j = 0; j < i; j++)
183                         device_remove_file(&dev->dev, &device_attrs[i]);
184         device_unregister(&dev->dev);
185 err_out:
186
187         return err;
188 }
189
190 /**
191  * drm_sysfs_device_remove - remove DRM device
192  * @dev: DRM device to remove
193  *
194  * This call unregisters and cleans up a class device that was created with a
195  * call to drm_sysfs_device_add()
196  */
197 void drm_sysfs_device_remove(struct drm_device *dev)
198 {
199         int i;
200
201         for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
202                 device_remove_file(&dev->dev, &device_attrs[i]);
203         device_unregister(&dev->dev);
204 }