Blame view

drivers/base/class.c 15.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
  /*
   * class.c - basic device class management
   *
   * Copyright (c) 2002-3 Patrick Mochel
   * Copyright (c) 2002-3 Open Source Development Labs
   * Copyright (c) 2003-2004 Greg Kroah-Hartman
   * Copyright (c) 2003-2004 IBM Corp.
   *
   * This file is released under the GPLv2
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
  #include <linux/device.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/string.h>
  #include <linux/kdev_t.h>
e9ba6365f   Greg Kroah-Hartman   [PATCH] CLASS: mo...
17
  #include <linux/err.h>
4e57b6817   Tim Schmielau   [PATCH] fix missi...
18
  #include <linux/slab.h>
edfaa7c36   Kay Sievers   Driver core: conv...
19
  #include <linux/genhd.h>
f75b1c60f   Dave Young   class: change int...
20
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
  #include "base.h"
  
  #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24

4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
25
26
  static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr,
  			       char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  {
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
28
  	struct class_attribute *class_attr = to_class_attr(attr);
6b6e39a6a   Kay Sievers   driver-core: merg...
29
  	struct subsys_private *cp = to_subsys_private(kobj);
4a0c20bf8   Dmitry Torokhov   [PATCH] sysfs: (d...
30
  	ssize_t ret = -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
  
  	if (class_attr->show)
28812fe11   Andi Kleen   driver-core: Add ...
33
  		ret = class_attr->show(cp->class, class_attr, buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
  	return ret;
  }
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
36
37
  static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr,
  				const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  {
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
39
  	struct class_attribute *class_attr = to_class_attr(attr);
6b6e39a6a   Kay Sievers   driver-core: merg...
40
  	struct subsys_private *cp = to_subsys_private(kobj);
4a0c20bf8   Dmitry Torokhov   [PATCH] sysfs: (d...
41
  	ssize_t ret = -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
  
  	if (class_attr->store)
28812fe11   Andi Kleen   driver-core: Add ...
44
  		ret = class_attr->store(cp->class, class_attr, buf, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
  	return ret;
  }
672d82c18   Eric W. Biederman   class: Implement ...
47
48
49
50
51
52
53
54
55
56
57
  static const void *class_attr_namespace(struct kobject *kobj,
  					const struct attribute *attr)
  {
  	struct class_attribute *class_attr = to_class_attr(attr);
  	struct subsys_private *cp = to_subsys_private(kobj);
  	const void *ns = NULL;
  
  	if (class_attr->namespace)
  		ns = class_attr->namespace(cp->class, class_attr);
  	return ns;
  }
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
58
  static void class_release(struct kobject *kobj)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  {
6b6e39a6a   Kay Sievers   driver-core: merg...
60
  	struct subsys_private *cp = to_subsys_private(kobj);
7c71448b8   Greg Kroah-Hartman   class: move drive...
61
  	struct class *class = cp->class;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
68
69
70
71
  
  	pr_debug("class '%s': release.
  ", class->name);
  
  	if (class->class_release)
  		class->class_release(class);
  	else
  		pr_debug("class '%s' does not have a release() function, "
  			 "be careful
  ", class->name);
18d19c964   Laurent Pinchart   class: Free the c...
72
73
  
  	kfree(cp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  }
bc451f205   Eric W. Biederman   kobj: Add basic i...
75
76
  static const struct kobj_ns_type_operations *class_child_ns_type(struct kobject *kobj)
  {
6b6e39a6a   Kay Sievers   driver-core: merg...
77
  	struct subsys_private *cp = to_subsys_private(kobj);
bc451f205   Eric W. Biederman   kobj: Add basic i...
78
79
80
81
  	struct class *class = cp->class;
  
  	return class->ns_type;
  }
52cf25d0a   Emese Revfy   Driver core: Cons...
82
  static const struct sysfs_ops class_sysfs_ops = {
672d82c18   Eric W. Biederman   class: Implement ...
83
84
85
  	.show	   = class_attr_show,
  	.store	   = class_attr_store,
  	.namespace = class_attr_namespace,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
  };
adc56808f   Greg Kroah-Hartman   Driver core: rena...
87
  static struct kobj_type class_ktype = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
  	.sysfs_ops	= &class_sysfs_ops,
  	.release	= class_release,
bc451f205   Eric W. Biederman   kobj: Add basic i...
90
  	.child_ns_type	= class_child_ns_type,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  };
6b6e39a6a   Kay Sievers   driver-core: merg...
92
  /* Hotplug events for classes go to the class subsys */
443dbf900   Greg Kroah-Hartman   kset: convert dri...
93
  static struct kset *class_kset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94

4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
95
  int class_create_file(struct class *cls, const struct class_attribute *attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
  {
  	int error;
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
98
  	if (cls)
6b6e39a6a   Kay Sievers   driver-core: merg...
99
  		error = sysfs_create_file(&cls->p->subsys.kobj,
1fbfee6c6   Greg Kroah-Hartman   class: rename "su...
100
  					  &attr->attr);
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
101
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
  		error = -EINVAL;
  	return error;
  }
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
105
  void class_remove_file(struct class *cls, const struct class_attribute *attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
  {
  	if (cls)
6b6e39a6a   Kay Sievers   driver-core: merg...
108
  		sysfs_remove_file(&cls->p->subsys.kobj, &attr->attr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  }
1740757e8   Greg Kroah-Hartman   [PATCH] Driver Co...
110
  static struct class *class_get(struct class *cls)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
  {
  	if (cls)
6b6e39a6a   Kay Sievers   driver-core: merg...
113
  		kset_get(&cls->p->subsys);
7c71448b8   Greg Kroah-Hartman   class: move drive...
114
  	return cls;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  }
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
116
  static void class_put(struct class *cls)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  {
51d172d5f   Greg Kroah-Hartman   [PATCH] Driver Co...
118
  	if (cls)
6b6e39a6a   Kay Sievers   driver-core: merg...
119
  		kset_put(&cls->p->subsys);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  }
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
121
  static int add_class_attrs(struct class *cls)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
126
127
  {
  	int i;
  	int error = 0;
  
  	if (cls->class_attrs) {
  		for (i = 0; attr_name(cls->class_attrs[i]); i++) {
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
128
  			error = class_create_file(cls, &cls->class_attrs[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  			if (error)
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
130
  				goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
  		}
  	}
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
133
  done:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  	return error;
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
135
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  	while (--i >= 0)
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
137
138
  		class_remove_file(cls, &cls->class_attrs[i]);
  	goto done;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  }
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
140
  static void remove_class_attrs(struct class *cls)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
145
  {
  	int i;
  
  	if (cls->class_attrs) {
  		for (i = 0; attr_name(cls->class_attrs[i]); i++)
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
146
  			class_remove_file(cls, &cls->class_attrs[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
  	}
  }
5a3ceb861   Tejun Heo   driver-core: use ...
149
150
151
152
153
154
155
156
157
158
159
160
161
  static void klist_class_dev_get(struct klist_node *n)
  {
  	struct device *dev = container_of(n, struct device, knode_class);
  
  	get_device(dev);
  }
  
  static void klist_class_dev_put(struct klist_node *n)
  {
  	struct device *dev = container_of(n, struct device, knode_class);
  
  	put_device(dev);
  }
d2a3b9146   Matthew Wilcox   class: add lockde...
162
  int __class_register(struct class *cls, struct lock_class_key *key)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  {
6b6e39a6a   Kay Sievers   driver-core: merg...
164
  	struct subsys_private *cp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
168
  	int error;
  
  	pr_debug("device class '%s': registering
  ", cls->name);
7c71448b8   Greg Kroah-Hartman   class: move drive...
169
170
171
  	cp = kzalloc(sizeof(*cp), GFP_KERNEL);
  	if (!cp)
  		return -ENOMEM;
6b6e39a6a   Kay Sievers   driver-core: merg...
172
  	klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put);
ca22e56de   Kay Sievers   driver-core: impl...
173
  	INIT_LIST_HEAD(&cp->interfaces);
6b6e39a6a   Kay Sievers   driver-core: merg...
174
  	kset_init(&cp->glue_dirs);
ca22e56de   Kay Sievers   driver-core: impl...
175
  	__mutex_init(&cp->mutex, "subsys mutex", key);
6b6e39a6a   Kay Sievers   driver-core: merg...
176
  	error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);
7c71448b8   Greg Kroah-Hartman   class: move drive...
177
178
  	if (error) {
  		kfree(cp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  		return error;
7c71448b8   Greg Kroah-Hartman   class: move drive...
180
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181

e105b8bfc   Dan Williams   sysfs: add /sys/d...
182
183
184
  	/* set the default /sys/dev directory for devices of this class */
  	if (!cls->dev_kobj)
  		cls->dev_kobj = sysfs_dev_char_kobj;
e52eec13c   Andi Kleen   SYSFS: Allow boot...
185
  #if defined(CONFIG_BLOCK)
edfaa7c36   Kay Sievers   Driver core: conv...
186
  	/* let the block class directory show up in the root of sysfs */
e52eec13c   Andi Kleen   SYSFS: Allow boot...
187
  	if (!sysfs_deprecated || cls != &block_class)
6b6e39a6a   Kay Sievers   driver-core: merg...
188
  		cp->subsys.kobj.kset = class_kset;
edfaa7c36   Kay Sievers   Driver core: conv...
189
  #else
6b6e39a6a   Kay Sievers   driver-core: merg...
190
  	cp->subsys.kobj.kset = class_kset;
edfaa7c36   Kay Sievers   Driver core: conv...
191
  #endif
6b6e39a6a   Kay Sievers   driver-core: merg...
192
  	cp->subsys.kobj.ktype = &class_ktype;
7c71448b8   Greg Kroah-Hartman   class: move drive...
193
194
  	cp->class = cls;
  	cls->p = cp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195

6b6e39a6a   Kay Sievers   driver-core: merg...
196
  	error = kset_register(&cp->subsys);
7c71448b8   Greg Kroah-Hartman   class: move drive...
197
198
199
  	if (error) {
  		kfree(cp);
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  	}
7c71448b8   Greg Kroah-Hartman   class: move drive...
201
202
  	error = add_class_attrs(class_get(cls));
  	class_put(cls);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
  	return error;
  }
d2a3b9146   Matthew Wilcox   class: add lockde...
205
  EXPORT_SYMBOL_GPL(__class_register);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206

4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
207
  void class_unregister(struct class *cls)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
211
  {
  	pr_debug("device class '%s': unregistering
  ", cls->name);
  	remove_class_attrs(cls);
6b6e39a6a   Kay Sievers   driver-core: merg...
212
  	kset_unregister(&cls->p->subsys);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  }
e9ba6365f   Greg Kroah-Hartman   [PATCH] CLASS: mo...
214
215
  static void class_create_release(struct class *cls)
  {
2b3a302a0   Harvey Harrison   driver core: repl...
216
217
  	pr_debug("%s called for %s
  ", __func__, cls->name);
e9ba6365f   Greg Kroah-Hartman   [PATCH] CLASS: mo...
218
219
  	kfree(cls);
  }
2fc68447d   Greg Kroah-Hartman   [PATCH] class: ad...
220
221
222
223
  /**
   * class_create - create a struct class structure
   * @owner: pointer to the module that is to "own" this struct class
   * @name: pointer to a string for the name of this class.
0e241ffd3   Randy Dunlap   locking: fix mute...
224
   * @key: the lock_class_key for this class; used by mutex lock debugging
2fc68447d   Greg Kroah-Hartman   [PATCH] class: ad...
225
226
   *
   * This is used to create a struct class pointer that can then be used
c3b19ff06   Kay Sievers   driver core: remo...
227
   * in calls to device_create().
2fc68447d   Greg Kroah-Hartman   [PATCH] class: ad...
228
   *
f0eae0ed3   Jani Nikula   driver-core: docu...
229
230
   * Returns &struct class pointer on success, or ERR_PTR() on error.
   *
2fc68447d   Greg Kroah-Hartman   [PATCH] class: ad...
231
232
233
   * Note, the pointer created here is to be destroyed when finished by
   * making a call to class_destroy().
   */
d2a3b9146   Matthew Wilcox   class: add lockde...
234
235
  struct class *__class_create(struct module *owner, const char *name,
  			     struct lock_class_key *key)
e9ba6365f   Greg Kroah-Hartman   [PATCH] CLASS: mo...
236
237
238
  {
  	struct class *cls;
  	int retval;
4aed0644d   Jiri Slaby   [PATCH] drivers/b...
239
  	cls = kzalloc(sizeof(*cls), GFP_KERNEL);
e9ba6365f   Greg Kroah-Hartman   [PATCH] CLASS: mo...
240
241
242
243
  	if (!cls) {
  		retval = -ENOMEM;
  		goto error;
  	}
e9ba6365f   Greg Kroah-Hartman   [PATCH] CLASS: mo...
244
245
246
247
  
  	cls->name = name;
  	cls->owner = owner;
  	cls->class_release = class_create_release;
e9ba6365f   Greg Kroah-Hartman   [PATCH] CLASS: mo...
248

d2a3b9146   Matthew Wilcox   class: add lockde...
249
  	retval = __class_register(cls, key);
e9ba6365f   Greg Kroah-Hartman   [PATCH] CLASS: mo...
250
251
252
253
254
255
256
257
258
  	if (retval)
  		goto error;
  
  	return cls;
  
  error:
  	kfree(cls);
  	return ERR_PTR(retval);
  }
d2a3b9146   Matthew Wilcox   class: add lockde...
259
  EXPORT_SYMBOL_GPL(__class_create);
e9ba6365f   Greg Kroah-Hartman   [PATCH] CLASS: mo...
260

2fc68447d   Greg Kroah-Hartman   [PATCH] class: ad...
261
262
  /**
   * class_destroy - destroys a struct class structure
92a0f861f   Rolf Eike Beer   [PATCH] Fix param...
263
   * @cls: pointer to the struct class that is to be destroyed
2fc68447d   Greg Kroah-Hartman   [PATCH] class: ad...
264
265
266
267
   *
   * Note, the pointer to be destroyed must have been created with a call
   * to class_create().
   */
e9ba6365f   Greg Kroah-Hartman   [PATCH] CLASS: mo...
268
269
270
271
272
273
274
  void class_destroy(struct class *cls)
  {
  	if ((cls == NULL) || (IS_ERR(cls)))
  		return;
  
  	class_unregister(cls);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275

fd04897bb   Dave Young   Driver Core: add ...
276
  /**
5a3ceb861   Tejun Heo   driver-core: use ...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
   * class_dev_iter_init - initialize class device iterator
   * @iter: class iterator to initialize
   * @class: the class we wanna iterate over
   * @start: the device to start iterating from, if any
   * @type: device_type of the devices to iterate over, NULL for all
   *
   * Initialize class iterator @iter such that it iterates over devices
   * of @class.  If @start is set, the list iteration will start there,
   * otherwise if it is NULL, the iteration starts at the beginning of
   * the list.
   */
  void class_dev_iter_init(struct class_dev_iter *iter, struct class *class,
  			 struct device *start, const struct device_type *type)
  {
  	struct klist_node *start_knode = NULL;
  
  	if (start)
  		start_knode = &start->knode_class;
6b6e39a6a   Kay Sievers   driver-core: merg...
295
  	klist_iter_init_node(&class->p->klist_devices, &iter->ki, start_knode);
5a3ceb861   Tejun Heo   driver-core: use ...
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
  	iter->type = type;
  }
  EXPORT_SYMBOL_GPL(class_dev_iter_init);
  
  /**
   * class_dev_iter_next - iterate to the next device
   * @iter: class iterator to proceed
   *
   * Proceed @iter to the next device and return it.  Returns NULL if
   * iteration is complete.
   *
   * The returned device is referenced and won't be released till
   * iterator is proceed to the next device or exited.  The caller is
   * free to do whatever it wants to do with the device including
   * calling back into class code.
   */
  struct device *class_dev_iter_next(struct class_dev_iter *iter)
  {
  	struct klist_node *knode;
  	struct device *dev;
  
  	while (1) {
  		knode = klist_next(&iter->ki);
  		if (!knode)
  			return NULL;
  		dev = container_of(knode, struct device, knode_class);
  		if (!iter->type || iter->type == dev->type)
  			return dev;
  	}
  }
  EXPORT_SYMBOL_GPL(class_dev_iter_next);
  
  /**
   * class_dev_iter_exit - finish iteration
   * @iter: class iterator to finish
   *
   * Finish an iteration.  Always call this function after iteration is
   * complete whether the iteration ran till the end or not.
   */
  void class_dev_iter_exit(struct class_dev_iter *iter)
  {
  	klist_iter_exit(&iter->ki);
  }
  EXPORT_SYMBOL_GPL(class_dev_iter_exit);
  
  /**
fd04897bb   Dave Young   Driver Core: add ...
342
343
   * class_for_each_device - device iterator
   * @class: the class we're iterating
93562b537   Greg Kroah-Hartman   Driver Core: add ...
344
   * @start: the device to start with in the list, if any.
fd04897bb   Dave Young   Driver Core: add ...
345
346
347
348
   * @data: data for the callback
   * @fn: function to be called for each device
   *
   * Iterate over @class's list of devices, and call @fn for each,
93562b537   Greg Kroah-Hartman   Driver Core: add ...
349
350
351
   * passing it @data.  If @start is set, the list iteration will start
   * there, otherwise if it is NULL, the iteration starts at the
   * beginning of the list.
fd04897bb   Dave Young   Driver Core: add ...
352
353
354
355
   *
   * We check the return of @fn each time. If it returns anything
   * other than 0, we break out and return that value.
   *
5a3ceb861   Tejun Heo   driver-core: use ...
356
357
   * @fn is allowed to do anything including calling back into class
   * code.  There's no locking restriction.
fd04897bb   Dave Young   Driver Core: add ...
358
   */
93562b537   Greg Kroah-Hartman   Driver Core: add ...
359
360
  int class_for_each_device(struct class *class, struct device *start,
  			  void *data, int (*fn)(struct device *, void *))
fd04897bb   Dave Young   Driver Core: add ...
361
  {
5a3ceb861   Tejun Heo   driver-core: use ...
362
  	struct class_dev_iter iter;
fd04897bb   Dave Young   Driver Core: add ...
363
364
365
366
367
  	struct device *dev;
  	int error = 0;
  
  	if (!class)
  		return -EINVAL;
7c2250352   David Brownell   driver model: ant...
368
369
370
371
372
  	if (!class->p) {
  		WARN(1, "%s called for class '%s' before it was initialized",
  		     __func__, class->name);
  		return -EINVAL;
  	}
5a3ceb861   Tejun Heo   driver-core: use ...
373
374
  	class_dev_iter_init(&iter, class, start, NULL);
  	while ((dev = class_dev_iter_next(&iter))) {
93562b537   Greg Kroah-Hartman   Driver Core: add ...
375
  		error = fn(dev, data);
fd04897bb   Dave Young   Driver Core: add ...
376
377
378
  		if (error)
  			break;
  	}
5a3ceb861   Tejun Heo   driver-core: use ...
379
  	class_dev_iter_exit(&iter);
fd04897bb   Dave Young   Driver Core: add ...
380
381
382
383
384
385
386
387
  
  	return error;
  }
  EXPORT_SYMBOL_GPL(class_for_each_device);
  
  /**
   * class_find_device - device iterator for locating a particular device
   * @class: the class we're iterating
695794ae0   Greg Kroah-Hartman   Driver Core: add ...
388
   * @start: Device to begin with
fd04897bb   Dave Young   Driver Core: add ...
389
390
391
392
393
394
395
396
397
398
   * @data: data for the match function
   * @match: function to check device
   *
   * This is similar to the class_for_each_dev() function above, but it
   * returns a reference to a device that is 'found' for later use, as
   * determined by the @match callback.
   *
   * The callback should return 0 if the device doesn't match and non-zero
   * if it does.  If the callback returns non-zero, this function will
   * return to the caller and not iterate over any more devices.
a63ca8f65   Randy Dunlap   docbook: fix driv...
399
   *
fd04897bb   Dave Young   Driver Core: add ...
400
401
   * Note, you will need to drop the reference with put_device() after use.
   *
5a3ceb861   Tejun Heo   driver-core: use ...
402
403
   * @fn is allowed to do anything including calling back into class
   * code.  There's no locking restriction.
fd04897bb   Dave Young   Driver Core: add ...
404
   */
695794ae0   Greg Kroah-Hartman   Driver Core: add ...
405
406
407
  struct device *class_find_device(struct class *class, struct device *start,
  				 void *data,
  				 int (*match)(struct device *, void *))
fd04897bb   Dave Young   Driver Core: add ...
408
  {
5a3ceb861   Tejun Heo   driver-core: use ...
409
  	struct class_dev_iter iter;
fd04897bb   Dave Young   Driver Core: add ...
410
  	struct device *dev;
fd04897bb   Dave Young   Driver Core: add ...
411
412
413
  
  	if (!class)
  		return NULL;
7c2250352   David Brownell   driver model: ant...
414
415
416
417
418
  	if (!class->p) {
  		WARN(1, "%s called for class '%s' before it was initialized",
  		     __func__, class->name);
  		return NULL;
  	}
fd04897bb   Dave Young   Driver Core: add ...
419

5a3ceb861   Tejun Heo   driver-core: use ...
420
421
  	class_dev_iter_init(&iter, class, start, NULL);
  	while ((dev = class_dev_iter_next(&iter))) {
695794ae0   Greg Kroah-Hartman   Driver Core: add ...
422
  		if (match(dev, data)) {
5a3ceb861   Tejun Heo   driver-core: use ...
423
  			get_device(dev);
fd04897bb   Dave Young   Driver Core: add ...
424
  			break;
5a3ceb861   Tejun Heo   driver-core: use ...
425
  		}
fd04897bb   Dave Young   Driver Core: add ...
426
  	}
5a3ceb861   Tejun Heo   driver-core: use ...
427
  	class_dev_iter_exit(&iter);
fd04897bb   Dave Young   Driver Core: add ...
428

5a3ceb861   Tejun Heo   driver-core: use ...
429
  	return dev;
fd04897bb   Dave Young   Driver Core: add ...
430
431
  }
  EXPORT_SYMBOL_GPL(class_find_device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
434
  int class_interface_register(struct class_interface *class_intf)
  {
  	struct class *parent;
5a3ceb861   Tejun Heo   driver-core: use ...
435
  	struct class_dev_iter iter;
c47ed219b   Greg Kroah-Hartman   Class: add suppor...
436
  	struct device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
439
440
441
442
443
  
  	if (!class_intf || !class_intf->class)
  		return -ENODEV;
  
  	parent = class_get(class_intf->class);
  	if (!parent)
  		return -EINVAL;
ca22e56de   Kay Sievers   driver-core: impl...
444
445
  	mutex_lock(&parent->p->mutex);
  	list_add_tail(&class_intf->node, &parent->p->interfaces);
c47ed219b   Greg Kroah-Hartman   Class: add suppor...
446
  	if (class_intf->add_dev) {
5a3ceb861   Tejun Heo   driver-core: use ...
447
448
  		class_dev_iter_init(&iter, parent, NULL, NULL);
  		while ((dev = class_dev_iter_next(&iter)))
c47ed219b   Greg Kroah-Hartman   Class: add suppor...
449
  			class_intf->add_dev(dev, class_intf);
5a3ceb861   Tejun Heo   driver-core: use ...
450
  		class_dev_iter_exit(&iter);
c47ed219b   Greg Kroah-Hartman   Class: add suppor...
451
  	}
ca22e56de   Kay Sievers   driver-core: impl...
452
  	mutex_unlock(&parent->p->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
456
457
458
  
  	return 0;
  }
  
  void class_interface_unregister(struct class_interface *class_intf)
  {
4a3ad20cc   Greg Kroah-Hartman   Driver core: codi...
459
  	struct class *parent = class_intf->class;
5a3ceb861   Tejun Heo   driver-core: use ...
460
  	struct class_dev_iter iter;
c47ed219b   Greg Kroah-Hartman   Class: add suppor...
461
  	struct device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
  
  	if (!parent)
  		return;
ca22e56de   Kay Sievers   driver-core: impl...
465
  	mutex_lock(&parent->p->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
  	list_del_init(&class_intf->node);
c47ed219b   Greg Kroah-Hartman   Class: add suppor...
467
  	if (class_intf->remove_dev) {
5a3ceb861   Tejun Heo   driver-core: use ...
468
469
  		class_dev_iter_init(&iter, parent, NULL, NULL);
  		while ((dev = class_dev_iter_next(&iter)))
c47ed219b   Greg Kroah-Hartman   Class: add suppor...
470
  			class_intf->remove_dev(dev, class_intf);
5a3ceb861   Tejun Heo   driver-core: use ...
471
  		class_dev_iter_exit(&iter);
c47ed219b   Greg Kroah-Hartman   Class: add suppor...
472
  	}
ca22e56de   Kay Sievers   driver-core: impl...
473
  	mutex_unlock(&parent->p->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
  
  	class_put(parent);
  }
319684b1c   Brandon Philips   driver core: fix ...
477
478
  ssize_t show_class_attr_string(struct class *class,
  			       struct class_attribute *attr, char *buf)
869dfc875   Andi Kleen   driver core: Add ...
479
480
481
482
483
484
485
486
  {
  	struct class_attribute_string *cs;
  	cs = container_of(attr, struct class_attribute_string, attr);
  	return snprintf(buf, PAGE_SIZE, "%s
  ", cs->str);
  }
  
  EXPORT_SYMBOL_GPL(show_class_attr_string);
462270944   Jean Delvare   Driver core: Add ...
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
  struct class_compat {
  	struct kobject *kobj;
  };
  
  /**
   * class_compat_register - register a compatibility class
   * @name: the name of the class
   *
   * Compatibility class are meant as a temporary user-space compatibility
   * workaround when converting a family of class devices to a bus devices.
   */
  struct class_compat *class_compat_register(const char *name)
  {
  	struct class_compat *cls;
  
  	cls = kmalloc(sizeof(struct class_compat), GFP_KERNEL);
  	if (!cls)
  		return NULL;
  	cls->kobj = kobject_create_and_add(name, &class_kset->kobj);
  	if (!cls->kobj) {
  		kfree(cls);
  		return NULL;
  	}
  	return cls;
  }
  EXPORT_SYMBOL_GPL(class_compat_register);
  
  /**
   * class_compat_unregister - unregister a compatibility class
   * @cls: the class to unregister
   */
  void class_compat_unregister(struct class_compat *cls)
  {
  	kobject_put(cls->kobj);
  	kfree(cls);
  }
  EXPORT_SYMBOL_GPL(class_compat_unregister);
  
  /**
   * class_compat_create_link - create a compatibility class device link to
   *			      a bus device
   * @cls: the compatibility class
   * @dev: the target bus device
   * @device_link: an optional device to which a "device" link should be created
   */
  int class_compat_create_link(struct class_compat *cls, struct device *dev,
  			     struct device *device_link)
  {
  	int error;
  
  	error = sysfs_create_link(cls->kobj, &dev->kobj, dev_name(dev));
  	if (error)
  		return error;
  
  	/*
  	 * Optionally add a "device" link (typically to the parent), as a
  	 * class device would have one and we want to provide as much
  	 * backwards compatibility as possible.
  	 */
  	if (device_link) {
  		error = sysfs_create_link(&dev->kobj, &device_link->kobj,
  					  "device");
  		if (error)
  			sysfs_remove_link(cls->kobj, dev_name(dev));
  	}
  
  	return error;
  }
  EXPORT_SYMBOL_GPL(class_compat_create_link);
  
  /**
   * class_compat_remove_link - remove a compatibility class device link to
   *			      a bus device
   * @cls: the compatibility class
   * @dev: the target bus device
   * @device_link: an optional device to which a "device" link was previously
   * 		 created
   */
  void class_compat_remove_link(struct class_compat *cls, struct device *dev,
  			      struct device *device_link)
  {
  	if (device_link)
  		sysfs_remove_link(&dev->kobj, "device");
  	sysfs_remove_link(cls->kobj, dev_name(dev));
  }
  EXPORT_SYMBOL_GPL(class_compat_remove_link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
  int __init classes_init(void)
  {
443dbf900   Greg Kroah-Hartman   kset: convert dri...
575
576
577
  	class_kset = kset_create_and_add("class", NULL, NULL);
  	if (!class_kset)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
580
581
582
  	return 0;
  }
  
  EXPORT_SYMBOL_GPL(class_create_file);
  EXPORT_SYMBOL_GPL(class_remove_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  EXPORT_SYMBOL_GPL(class_unregister);
e9ba6365f   Greg Kroah-Hartman   [PATCH] CLASS: mo...
584
  EXPORT_SYMBOL_GPL(class_destroy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
  EXPORT_SYMBOL_GPL(class_interface_register);
  EXPORT_SYMBOL_GPL(class_interface_unregister);