Create new linux-2.6 build. Move all gpl files into the 2.6 build. If you
[platform/upstream/libdrm.git] / linux-core / drm_sysfs.c
1 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
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/config.h>
16 #include <linux/device.h>
17 #include <linux/kdev_t.h>
18 #include <linux/err.h>
19
20 struct drm_sysfs_class {
21         struct class_device_attribute attr;
22         struct class class;
23 };
24 #define to_drm_sysfs_class(d) container_of(d, struct drm_sysfs_class, class)
25
26 struct simple_dev {
27         struct list_head node;
28         dev_t dev;
29         struct class_device class_dev;
30 };
31 #define to_simple_dev(d) container_of(d, struct simple_dev, class_dev)
32
33 static LIST_HEAD(simple_dev_list);
34 static spinlock_t simple_dev_list_lock = SPIN_LOCK_UNLOCKED;
35
36 static void release_simple_dev(struct class_device *class_dev)
37 {
38         struct simple_dev *s_dev = to_simple_dev(class_dev);
39         kfree(s_dev);
40 }
41
42 static ssize_t show_dev(struct class_device *class_dev, char *buf)
43 {
44         struct simple_dev *s_dev = to_simple_dev(class_dev);
45         return print_dev_t(buf, s_dev->dev);
46 }
47
48 static void drm_sysfs_class_release(struct class *class)
49 {
50         struct drm_sysfs_class *cs = to_drm_sysfs_class(class);
51         kfree(cs);
52 }
53
54 /* Display the version of drm_core. This doesn't work right in current design */
55 static ssize_t version_show(struct class *dev, char *buf)
56 {
57         return sprintf(buf, "fixme for drm_core %s %d.%d.%d %s\n", DRIVER_NAME, DRIVER_MAJOR, 
58                                 DRIVER_MINOR, DRIVER_PATCHLEVEL, DRIVER_DATE);
59 }
60 static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
61
62 /**
63  * DRM(sysfs_create) - create a struct drm_sysfs_class structure
64  * @owner: pointer to the module that is to "own" this struct drm_sysfs_class
65  * @name: pointer to a string for the name of this class.
66  *
67  * This is used to create a struct drm_sysfs_class pointer that can then be used
68  * in calls to DRM(sysfs_device_add)().
69  *
70  * Note, the pointer created here is to be destroyed when finished by making a
71  * call to DRM(sysfs_destroy)().
72  */
73 struct drm_sysfs_class *DRM(sysfs_create)(struct module *owner, char *name)
74 {
75         struct drm_sysfs_class *cs;
76         int retval;
77
78         cs = kmalloc(sizeof(*cs), GFP_KERNEL);
79         if (!cs) {
80                 retval = -ENOMEM;
81                 goto error;
82         }
83         memset(cs, 0x00, sizeof(*cs));
84
85         cs->class.name = name;
86         cs->class.class_release = drm_sysfs_class_release;
87         cs->class.release = release_simple_dev;
88
89         cs->attr.attr.name = "dev";
90         cs->attr.attr.mode = S_IRUGO;
91         cs->attr.attr.owner = owner;
92         cs->attr.show = show_dev;
93         cs->attr.store = NULL;
94
95         retval = class_register(&cs->class);
96         if (retval)
97                 goto error;
98         class_create_file(&cs->class, &class_attr_version);
99
100         return cs;
101
102 error:
103         kfree(cs);
104         return ERR_PTR(retval);
105 }
106
107 /**
108  * DRM(sysfs_destroy) - destroys a struct drm_sysfs_class structure
109  * @cs: pointer to the struct drm_sysfs_class that is to be destroyed
110  *
111  * Note, the pointer to be destroyed must have been created with a call to
112  * DRM(sysfs_create)().
113  */
114 void DRM(sysfs_destroy)(struct drm_sysfs_class *cs)
115 {
116         if ((cs == NULL) || (IS_ERR(cs)))
117                 return;
118
119         class_unregister(&cs->class);
120 }
121
122 /**
123  * DRM(sysfs_device_add) - adds a class device to sysfs for a character driver
124  * @cs: pointer to the struct drm_sysfs_class that this device should be registered to.
125  * @dev: the dev_t for the device to be added.
126  * @device: a pointer to a struct device that is assiociated with this class device.
127  * @fmt: string for the class device's name
128  *
129  * A struct class_device will be created in sysfs, registered to the specified 
130  * class.  A "dev" file will be created, showing the dev_t for the device.  The 
131  * pointer to the struct class_device will be returned from the call.  Any further
132  * sysfs files that might be required can be created using this pointer.
133  * Note: the struct drm_sysfs_class passed to this function must have previously been
134  * created with a call to DRM(sysfs_create)().
135  */
136 struct class_device *DRM(sysfs_device_add)(struct drm_sysfs_class *cs, dev_t dev, struct device *device, const char *fmt, ...)
137 {
138         va_list args;
139         struct simple_dev *s_dev = NULL;
140         int retval;
141
142         if ((cs == NULL) || (IS_ERR(cs))) {
143                 retval = -ENODEV;
144                 goto error;
145         }
146
147         s_dev = kmalloc(sizeof(*s_dev), GFP_KERNEL);
148         if (!s_dev) {
149                 retval = -ENOMEM;
150                 goto error;
151         }
152         memset(s_dev, 0x00, sizeof(*s_dev));
153
154         s_dev->dev = dev;
155         s_dev->class_dev.dev = device;
156         s_dev->class_dev.class = &cs->class;
157
158         va_start(args, fmt);
159         vsnprintf(s_dev->class_dev.class_id, BUS_ID_SIZE, fmt, args);
160         va_end(args);
161         retval = class_device_register(&s_dev->class_dev);
162         if (retval)
163                 goto error;
164
165         class_device_create_file(&s_dev->class_dev, &cs->attr);
166
167         spin_lock(&simple_dev_list_lock);
168         list_add(&s_dev->node, &simple_dev_list);
169         spin_unlock(&simple_dev_list_lock);
170
171         return &s_dev->class_dev;
172
173 error:
174         kfree(s_dev);
175         return ERR_PTR(retval);
176 }
177
178 /**
179  * DRM(sysfs_device_remove) - removes a class device that was created with DRM(sysfs_device_add)()
180  * @dev: the dev_t of the device that was previously registered.
181  *
182  * This call unregisters and cleans up a class device that was created with a
183  * call to DRM(sysfs_device_add)()
184  */
185 void DRM(sysfs_device_remove)(dev_t dev)
186 {
187         struct simple_dev *s_dev = NULL;
188         int found = 0;
189
190         spin_lock(&simple_dev_list_lock);
191         list_for_each_entry(s_dev, &simple_dev_list, node) {
192                 if (s_dev->dev == dev) {
193                         found = 1;
194                         break;
195                 }
196         }
197         if (found) {
198                 list_del(&s_dev->node);
199                 spin_unlock(&simple_dev_list_lock);
200                 class_device_unregister(&s_dev->class_dev);
201         } else {
202                 spin_unlock(&simple_dev_list_lock);
203         }
204 }
205
206 #endif