diff options
Diffstat (limited to 'drivers/base/class.c')
-rw-r--r-- | drivers/base/class.c | 87 |
1 files changed, 48 insertions, 39 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c index 3918d0e432d4..06f09c929a91 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
@@ -21,17 +21,16 @@ | |||
21 | #include "base.h" | 21 | #include "base.h" |
22 | 22 | ||
23 | #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) | 23 | #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) |
24 | #define to_class(obj) container_of(obj, struct class, subsys.kobj) | ||
25 | 24 | ||
26 | static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, | 25 | static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, |
27 | char *buf) | 26 | char *buf) |
28 | { | 27 | { |
29 | struct class_attribute *class_attr = to_class_attr(attr); | 28 | struct class_attribute *class_attr = to_class_attr(attr); |
30 | struct class *dc = to_class(kobj); | 29 | struct class_private *cp = to_class(kobj); |
31 | ssize_t ret = -EIO; | 30 | ssize_t ret = -EIO; |
32 | 31 | ||
33 | if (class_attr->show) | 32 | if (class_attr->show) |
34 | ret = class_attr->show(dc, buf); | 33 | ret = class_attr->show(cp->class, buf); |
35 | return ret; | 34 | return ret; |
36 | } | 35 | } |
37 | 36 | ||
@@ -39,17 +38,18 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, | |||
39 | const char *buf, size_t count) | 38 | const char *buf, size_t count) |
40 | { | 39 | { |
41 | struct class_attribute *class_attr = to_class_attr(attr); | 40 | struct class_attribute *class_attr = to_class_attr(attr); |
42 | struct class *dc = to_class(kobj); | 41 | struct class_private *cp = to_class(kobj); |
43 | ssize_t ret = -EIO; | 42 | ssize_t ret = -EIO; |
44 | 43 | ||
45 | if (class_attr->store) | 44 | if (class_attr->store) |
46 | ret = class_attr->store(dc, buf, count); | 45 | ret = class_attr->store(cp->class, buf, count); |
47 | return ret; | 46 | return ret; |
48 | } | 47 | } |
49 | 48 | ||
50 | static void class_release(struct kobject *kobj) | 49 | static void class_release(struct kobject *kobj) |
51 | { | 50 | { |
52 | struct class *class = to_class(kobj); | 51 | struct class_private *cp = to_class(kobj); |
52 | struct class *class = cp->class; | ||
53 | 53 | ||
54 | pr_debug("class '%s': release.\n", class->name); | 54 | pr_debug("class '%s': release.\n", class->name); |
55 | 55 | ||
@@ -78,7 +78,7 @@ int class_create_file(struct class *cls, const struct class_attribute *attr) | |||
78 | { | 78 | { |
79 | int error; | 79 | int error; |
80 | if (cls) | 80 | if (cls) |
81 | error = sysfs_create_file(&cls->subsys.kobj, &attr->attr); | 81 | error = sysfs_create_file(&cls->p->subsys.kobj, &attr->attr); |
82 | else | 82 | else |
83 | error = -EINVAL; | 83 | error = -EINVAL; |
84 | return error; | 84 | return error; |
@@ -87,21 +87,20 @@ int class_create_file(struct class *cls, const struct class_attribute *attr) | |||
87 | void class_remove_file(struct class *cls, const struct class_attribute *attr) | 87 | void class_remove_file(struct class *cls, const struct class_attribute *attr) |
88 | { | 88 | { |
89 | if (cls) | 89 | if (cls) |
90 | sysfs_remove_file(&cls->subsys.kobj, &attr->attr); | 90 | sysfs_remove_file(&cls->p->subsys.kobj, &attr->attr); |
91 | } | 91 | } |
92 | 92 | ||
93 | static struct class *class_get(struct class *cls) | 93 | static struct class *class_get(struct class *cls) |
94 | { | 94 | { |
95 | if (cls) | 95 | if (cls) |
96 | return container_of(kset_get(&cls->subsys), | 96 | kset_get(&cls->p->subsys); |
97 | struct class, subsys); | 97 | return cls; |
98 | return NULL; | ||
99 | } | 98 | } |
100 | 99 | ||
101 | static void class_put(struct class *cls) | 100 | static void class_put(struct class *cls) |
102 | { | 101 | { |
103 | if (cls) | 102 | if (cls) |
104 | kset_put(&cls->subsys); | 103 | kset_put(&cls->p->subsys); |
105 | } | 104 | } |
106 | 105 | ||
107 | static int add_class_attrs(struct class *cls) | 106 | static int add_class_attrs(struct class *cls) |
@@ -136,17 +135,23 @@ static void remove_class_attrs(struct class *cls) | |||
136 | 135 | ||
137 | int class_register(struct class *cls) | 136 | int class_register(struct class *cls) |
138 | { | 137 | { |
138 | struct class_private *cp; | ||
139 | int error; | 139 | int error; |
140 | 140 | ||
141 | pr_debug("device class '%s': registering\n", cls->name); | 141 | pr_debug("device class '%s': registering\n", cls->name); |
142 | 142 | ||
143 | INIT_LIST_HEAD(&cls->devices); | 143 | cp = kzalloc(sizeof(*cp), GFP_KERNEL); |
144 | INIT_LIST_HEAD(&cls->interfaces); | 144 | if (!cp) |
145 | kset_init(&cls->class_dirs); | 145 | return -ENOMEM; |
146 | init_MUTEX(&cls->sem); | 146 | INIT_LIST_HEAD(&cp->devices); |
147 | error = kobject_set_name(&cls->subsys.kobj, "%s", cls->name); | 147 | INIT_LIST_HEAD(&cp->interfaces); |
148 | if (error) | 148 | kset_init(&cp->class_dirs); |
149 | init_MUTEX(&cp->sem); | ||
150 | error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name); | ||
151 | if (error) { | ||
152 | kfree(cp); | ||
149 | return error; | 153 | return error; |
154 | } | ||
150 | 155 | ||
151 | /* set the default /sys/dev directory for devices of this class */ | 156 | /* set the default /sys/dev directory for devices of this class */ |
152 | if (!cls->dev_kobj) | 157 | if (!cls->dev_kobj) |
@@ -155,17 +160,21 @@ int class_register(struct class *cls) | |||
155 | #if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK) | 160 | #if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK) |
156 | /* let the block class directory show up in the root of sysfs */ | 161 | /* let the block class directory show up in the root of sysfs */ |
157 | if (cls != &block_class) | 162 | if (cls != &block_class) |
158 | cls->subsys.kobj.kset = class_kset; | 163 | cp->subsys.kobj.kset = class_kset; |
159 | #else | 164 | #else |
160 | cls->subsys.kobj.kset = class_kset; | 165 | cp->subsys.kobj.kset = class_kset; |
161 | #endif | 166 | #endif |
162 | cls->subsys.kobj.ktype = &class_ktype; | 167 | cp->subsys.kobj.ktype = &class_ktype; |
168 | cp->class = cls; | ||
169 | cls->p = cp; | ||
163 | 170 | ||
164 | error = kset_register(&cls->subsys); | 171 | error = kset_register(&cp->subsys); |
165 | if (!error) { | 172 | if (error) { |
166 | error = add_class_attrs(class_get(cls)); | 173 | kfree(cp); |
167 | class_put(cls); | 174 | return error; |
168 | } | 175 | } |
176 | error = add_class_attrs(class_get(cls)); | ||
177 | class_put(cls); | ||
169 | return error; | 178 | return error; |
170 | } | 179 | } |
171 | 180 | ||
@@ -173,7 +182,7 @@ void class_unregister(struct class *cls) | |||
173 | { | 182 | { |
174 | pr_debug("device class '%s': unregistering\n", cls->name); | 183 | pr_debug("device class '%s': unregistering\n", cls->name); |
175 | remove_class_attrs(cls); | 184 | remove_class_attrs(cls); |
176 | kset_unregister(&cls->subsys); | 185 | kset_unregister(&cls->p->subsys); |
177 | } | 186 | } |
178 | 187 | ||
179 | static void class_create_release(struct class *cls) | 188 | static void class_create_release(struct class *cls) |
@@ -280,8 +289,8 @@ int class_for_each_device(struct class *class, struct device *start, | |||
280 | 289 | ||
281 | if (!class) | 290 | if (!class) |
282 | return -EINVAL; | 291 | return -EINVAL; |
283 | down(&class->sem); | 292 | down(&class->p->sem); |
284 | list_for_each_entry(dev, &class->devices, node) { | 293 | list_for_each_entry(dev, &class->p->devices, node) { |
285 | if (start) { | 294 | if (start) { |
286 | if (start == dev) | 295 | if (start == dev) |
287 | start = NULL; | 296 | start = NULL; |
@@ -293,7 +302,7 @@ int class_for_each_device(struct class *class, struct device *start, | |||
293 | if (error) | 302 | if (error) |
294 | break; | 303 | break; |
295 | } | 304 | } |
296 | up(&class->sem); | 305 | up(&class->p->sem); |
297 | 306 | ||
298 | return error; | 307 | return error; |
299 | } | 308 | } |
@@ -330,8 +339,8 @@ struct device *class_find_device(struct class *class, struct device *start, | |||
330 | if (!class) | 339 | if (!class) |
331 | return NULL; | 340 | return NULL; |
332 | 341 | ||
333 | down(&class->sem); | 342 | down(&class->p->sem); |
334 | list_for_each_entry(dev, &class->devices, node) { | 343 | list_for_each_entry(dev, &class->p->devices, node) { |
335 | if (start) { | 344 | if (start) { |
336 | if (start == dev) | 345 | if (start == dev) |
337 | start = NULL; | 346 | start = NULL; |
@@ -344,7 +353,7 @@ struct device *class_find_device(struct class *class, struct device *start, | |||
344 | } else | 353 | } else |
345 | put_device(dev); | 354 | put_device(dev); |
346 | } | 355 | } |
347 | up(&class->sem); | 356 | up(&class->p->sem); |
348 | 357 | ||
349 | return found ? dev : NULL; | 358 | return found ? dev : NULL; |
350 | } | 359 | } |
@@ -362,13 +371,13 @@ int class_interface_register(struct class_interface *class_intf) | |||
362 | if (!parent) | 371 | if (!parent) |
363 | return -EINVAL; | 372 | return -EINVAL; |
364 | 373 | ||
365 | down(&parent->sem); | 374 | down(&parent->p->sem); |
366 | list_add_tail(&class_intf->node, &parent->interfaces); | 375 | list_add_tail(&class_intf->node, &parent->p->interfaces); |
367 | if (class_intf->add_dev) { | 376 | if (class_intf->add_dev) { |
368 | list_for_each_entry(dev, &parent->devices, node) | 377 | list_for_each_entry(dev, &parent->p->devices, node) |
369 | class_intf->add_dev(dev, class_intf); | 378 | class_intf->add_dev(dev, class_intf); |
370 | } | 379 | } |
371 | up(&parent->sem); | 380 | up(&parent->p->sem); |
372 | 381 | ||
373 | return 0; | 382 | return 0; |
374 | } | 383 | } |
@@ -381,13 +390,13 @@ void class_interface_unregister(struct class_interface *class_intf) | |||
381 | if (!parent) | 390 | if (!parent) |
382 | return; | 391 | return; |
383 | 392 | ||
384 | down(&parent->sem); | 393 | down(&parent->p->sem); |
385 | list_del_init(&class_intf->node); | 394 | list_del_init(&class_intf->node); |
386 | if (class_intf->remove_dev) { | 395 | if (class_intf->remove_dev) { |
387 | list_for_each_entry(dev, &parent->devices, node) | 396 | list_for_each_entry(dev, &parent->p->devices, node) |
388 | class_intf->remove_dev(dev, class_intf); | 397 | class_intf->remove_dev(dev, class_intf); |
389 | } | 398 | } |
390 | up(&parent->sem); | 399 | up(&parent->p->sem); |
391 | 400 | ||
392 | class_put(parent); | 401 | class_put(parent); |
393 | } | 402 | } |