1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/config.h>
16#include <linux/sysdev.h>
17#include <linux/err.h>
18#include <linux/module.h>
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/slab.h>
22#include <linux/string.h>
23
24
25extern struct subsystem devices_subsys;
26
27#define to_sysdev(k) container_of(k, struct sys_device, kobj)
28#define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr)
29
30
31static ssize_t
32sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer)
33{
34 struct sys_device * sysdev = to_sysdev(kobj);
35 struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
36
37 if (sysdev_attr->show)
38 return sysdev_attr->show(sysdev, buffer);
39 return 0;
40}
41
42
43static ssize_t
44sysdev_store(struct kobject * kobj, struct attribute * attr,
45 const char * buffer, size_t count)
46{
47 struct sys_device * sysdev = to_sysdev(kobj);
48 struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
49
50 if (sysdev_attr->store)
51 return sysdev_attr->store(sysdev, buffer, count);
52 return 0;
53}
54
55static struct sysfs_ops sysfs_ops = {
56 .show = sysdev_show,
57 .store = sysdev_store,
58};
59
60static struct kobj_type ktype_sysdev = {
61 .sysfs_ops = &sysfs_ops,
62};
63
64
65int sysdev_create_file(struct sys_device * s, struct sysdev_attribute * a)
66{
67 return sysfs_create_file(&s->kobj, &a->attr);
68}
69
70
71void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a)
72{
73 sysfs_remove_file(&s->kobj, &a->attr);
74}
75
76EXPORT_SYMBOL_GPL(sysdev_create_file);
77EXPORT_SYMBOL_GPL(sysdev_remove_file);
78
79
80
81
82decl_subsys(system, &ktype_sysdev, NULL);
83
84int sysdev_class_register(struct sysdev_class * cls)
85{
86 pr_debug("Registering sysdev class '%s'\n",
87 kobject_name(&cls->kset.kobj));
88 INIT_LIST_HEAD(&cls->drivers);
89 cls->kset.subsys = &system_subsys;
90 kset_set_kset_s(cls, system_subsys);
91 return kset_register(&cls->kset);
92}
93
94void sysdev_class_unregister(struct sysdev_class * cls)
95{
96 pr_debug("Unregistering sysdev class '%s'\n",
97 kobject_name(&cls->kset.kobj));
98 kset_unregister(&cls->kset);
99}
100
101EXPORT_SYMBOL_GPL(sysdev_class_register);
102EXPORT_SYMBOL_GPL(sysdev_class_unregister);
103
104
105static LIST_HEAD(global_drivers);
106
107
108
109
110
111
112
113
114
115
116
117
118
119int sysdev_driver_register(struct sysdev_class * cls,
120 struct sysdev_driver * drv)
121{
122 down_write(&system_subsys.rwsem);
123 if (cls && kset_get(&cls->kset)) {
124 list_add_tail(&drv->entry, &cls->drivers);
125
126
127 if (drv->add) {
128 struct sys_device *dev;
129 list_for_each_entry(dev, &cls->kset.list, kobj.entry)
130 drv->add(dev);
131 }
132 } else
133 list_add_tail(&drv->entry, &global_drivers);
134 up_write(&system_subsys.rwsem);
135 return 0;
136}
137
138
139
140
141
142
143
144void sysdev_driver_unregister(struct sysdev_class * cls,
145 struct sysdev_driver * drv)
146{
147 down_write(&system_subsys.rwsem);
148 list_del_init(&drv->entry);
149 if (cls) {
150 if (drv->remove) {
151 struct sys_device *dev;
152 list_for_each_entry(dev, &cls->kset.list, kobj.entry)
153 drv->remove(dev);
154 }
155 kset_put(&cls->kset);
156 }
157 up_write(&system_subsys.rwsem);
158}
159
160EXPORT_SYMBOL_GPL(sysdev_driver_register);
161EXPORT_SYMBOL_GPL(sysdev_driver_unregister);
162
163
164
165
166
167
168
169
170int sysdev_register(struct sys_device * sysdev)
171{
172 int error;
173 struct sysdev_class * cls = sysdev->cls;
174
175 if (!cls)
176 return -EINVAL;
177
178
179 sysdev->kobj.kset = &cls->kset;
180
181
182 sysdev->kobj.ktype = &ktype_sysdev;
183 error = kobject_set_name(&sysdev->kobj, "%s%d",
184 kobject_name(&cls->kset.kobj), sysdev->id);
185 if (error)
186 return error;
187
188 pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj));
189
190
191 error = kobject_register(&sysdev->kobj);
192
193 if (!error) {
194 struct sysdev_driver * drv;
195
196 down_write(&system_subsys.rwsem);
197
198
199
200
201
202 list_for_each_entry(drv, &global_drivers, entry) {
203 if (drv->add)
204 drv->add(sysdev);
205 }
206
207
208 list_for_each_entry(drv, &cls->drivers, entry) {
209 if (drv->add)
210 drv->add(sysdev);
211 }
212 up_write(&system_subsys.rwsem);
213 }
214 return error;
215}
216
217void sysdev_unregister(struct sys_device * sysdev)
218{
219 struct sysdev_driver * drv;
220
221 down_write(&system_subsys.rwsem);
222 list_for_each_entry(drv, &global_drivers, entry) {
223 if (drv->remove)
224 drv->remove(sysdev);
225 }
226
227 list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
228 if (drv->remove)
229 drv->remove(sysdev);
230 }
231 up_write(&system_subsys.rwsem);
232
233 kobject_unregister(&sysdev->kobj);
234}
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252void sysdev_shutdown(void)
253{
254 struct sysdev_class * cls;
255
256 pr_debug("Shutting Down System Devices\n");
257
258 down_write(&system_subsys.rwsem);
259 list_for_each_entry_reverse(cls, &system_subsys.kset.list,
260 kset.kobj.entry) {
261 struct sys_device * sysdev;
262
263 pr_debug("Shutting down type '%s':\n",
264 kobject_name(&cls->kset.kobj));
265
266 list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
267 struct sysdev_driver * drv;
268 pr_debug(" %s\n", kobject_name(&sysdev->kobj));
269
270
271 list_for_each_entry(drv, &global_drivers, entry) {
272 if (drv->shutdown)
273 drv->shutdown(sysdev);
274 }
275
276
277 list_for_each_entry(drv, &cls->drivers, entry) {
278 if (drv->shutdown)
279 drv->shutdown(sysdev);
280 }
281
282
283 if (cls->shutdown)
284 cls->shutdown(sysdev);
285 }
286 }
287 up_write(&system_subsys.rwsem);
288}
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304int sysdev_suspend(u32 state)
305{
306 struct sysdev_class * cls;
307
308 pr_debug("Suspending System Devices\n");
309
310 list_for_each_entry_reverse(cls, &system_subsys.kset.list,
311 kset.kobj.entry) {
312 struct sys_device * sysdev;
313
314 pr_debug("Suspending type '%s':\n",
315 kobject_name(&cls->kset.kobj));
316
317 list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
318 struct sysdev_driver * drv;
319 pr_debug(" %s\n", kobject_name(&sysdev->kobj));
320
321
322 list_for_each_entry(drv, &global_drivers, entry) {
323 if (drv->suspend)
324 drv->suspend(sysdev, state);
325 }
326
327
328 list_for_each_entry(drv, &cls->drivers, entry) {
329 if (drv->suspend)
330 drv->suspend(sysdev, state);
331 }
332
333
334 if (cls->suspend)
335 cls->suspend(sysdev, state);
336 }
337 }
338 return 0;
339}
340
341
342
343
344
345
346
347
348
349
350
351int sysdev_resume(void)
352{
353 struct sysdev_class * cls;
354
355 pr_debug("Resuming System Devices\n");
356
357 list_for_each_entry(cls, &system_subsys.kset.list, kset.kobj.entry) {
358 struct sys_device * sysdev;
359
360 pr_debug("Resuming type '%s':\n",
361 kobject_name(&cls->kset.kobj));
362
363 list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
364 struct sysdev_driver * drv;
365 pr_debug(" %s\n", kobject_name(&sysdev->kobj));
366
367
368 if (cls->resume)
369 cls->resume(sysdev);
370
371
372 list_for_each_entry(drv, &cls->drivers, entry) {
373 if (drv->resume)
374 drv->resume(sysdev);
375 }
376
377
378 list_for_each_entry(drv, &global_drivers, entry) {
379 if (drv->resume)
380 drv->resume(sysdev);
381 }
382
383 }
384 }
385 return 0;
386}
387
388
389int __init system_bus_init(void)
390{
391 system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj;
392 return subsystem_register(&system_subsys);
393}
394
395EXPORT_SYMBOL_GPL(sysdev_register);
396EXPORT_SYMBOL_GPL(sysdev_unregister);
397