Blame view

drivers/base/attribute_container.c 14.4 KB
989d42e85   Greg Kroah-Hartman   driver core: add ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
   * attribute_container.c - implementation of a simple container for classes
   *
   * Copyright (c) 2005 - James Bottomley <James.Bottomley@steeleye.com>
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
   * The basic idea here is to enable a device to be attached to an
   * aritrary numer of classes without having to allocate storage for them.
   * Instead, the contained classes select the devices they need to attach
   * to via a matching function.
   */
  
  #include <linux/attribute_container.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
  #include <linux/device.h>
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include <linux/list.h>
  #include <linux/module.h>
f8916c11a   Michael S. Tsirkin   Driver core: incl...
19
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20

a1bdc7aad   Ben Dooks   [PATCH] drivers/b...
21
  #include "base.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
  /* This is a private structure used to tie the classdev and the
   * container .. it should never be visible outside this file */
  struct internal_container {
53c165e0a   James Bottomley   [SCSI] correct at...
25
  	struct klist_node node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  	struct attribute_container *cont;
ee959b00c   Tony Jones   SCSI: convert str...
27
  	struct device classdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  };
caf39e87c   Linus Torvalds   [SCSI] Re-do "fin...
29
30
31
32
  static void internal_container_klist_get(struct klist_node *n)
  {
  	struct internal_container *ic =
  		container_of(n, struct internal_container, node);
ee959b00c   Tony Jones   SCSI: convert str...
33
  	get_device(&ic->classdev);
caf39e87c   Linus Torvalds   [SCSI] Re-do "fin...
34
35
36
37
38
39
  }
  
  static void internal_container_klist_put(struct klist_node *n)
  {
  	struct internal_container *ic =
  		container_of(n, struct internal_container, node);
ee959b00c   Tony Jones   SCSI: convert str...
40
  	put_device(&ic->classdev);
caf39e87c   Linus Torvalds   [SCSI] Re-do "fin...
41
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
  /**
   * attribute_container_classdev_to_container - given a classdev, return the container
   *
   * @classdev: the class device created by attribute_container_add_device.
   *
   * Returns the container associated with this classdev.
   */
  struct attribute_container *
ee959b00c   Tony Jones   SCSI: convert str...
50
  attribute_container_classdev_to_container(struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
54
55
56
  {
  	struct internal_container *ic =
  		container_of(classdev, struct internal_container, classdev);
  	return ic->cont;
  }
  EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container);
db1118a46   Denis Cheng   Driver core: use ...
57
  static LIST_HEAD(attribute_container_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

61a2f59af   Matthias Kaehlcke   drivers/base/attr...
59
  static DEFINE_MUTEX(attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
64
65
66
67
68
69
70
  
  /**
   * attribute_container_register - register an attribute container
   *
   * @cont: The container to register.  This must be allocated by the
   *        callee and should also be zeroed by it.
   */
  int
  attribute_container_register(struct attribute_container *cont)
  {
  	INIT_LIST_HEAD(&cont->node);
287f9bd93   Tina Johnson   attribute_contain...
71
  	klist_init(&cont->containers, internal_container_klist_get,
caf39e87c   Linus Torvalds   [SCSI] Re-do "fin...
72
  		   internal_container_klist_put);
24a7d36a7   Tina Johnson   attribute_contain...
73

61a2f59af   Matthias Kaehlcke   drivers/base/attr...
74
  	mutex_lock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  	list_add_tail(&cont->node, &attribute_container_list);
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
76
  	mutex_unlock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(attribute_container_register);
  
  /**
   * attribute_container_unregister - remove a container registration
   *
   * @cont: previously registered container to remove
   */
  int
  attribute_container_unregister(struct attribute_container *cont)
  {
  	int retval = -EBUSY;
481026dbe   Cosmin Dragomir   attribute_contain...
91

61a2f59af   Matthias Kaehlcke   drivers/base/attr...
92
  	mutex_lock(&attribute_container_mutex);
53c165e0a   James Bottomley   [SCSI] correct at...
93
94
  	spin_lock(&cont->containers.k_lock);
  	if (!list_empty(&cont->containers.k_list))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
  		goto out;
  	retval = 0;
  	list_del(&cont->node);
   out:
53c165e0a   James Bottomley   [SCSI] correct at...
99
  	spin_unlock(&cont->containers.k_lock);
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
100
  	mutex_unlock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  	return retval;
24a7d36a7   Tina Johnson   attribute_contain...
102

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
  }
  EXPORT_SYMBOL_GPL(attribute_container_unregister);
  
  /* private function used as class release */
ee959b00c   Tony Jones   SCSI: convert str...
107
  static void attribute_container_release(struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
  {
24a7d36a7   Tina Johnson   attribute_contain...
109
  	struct internal_container *ic
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  		= container_of(classdev, struct internal_container, classdev);
ee959b00c   Tony Jones   SCSI: convert str...
111
  	struct device *dev = classdev->parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  
  	kfree(ic);
  	put_device(dev);
  }
  
  /**
   * attribute_container_add_device - see if any container is interested in dev
   *
   * @dev: device to add attributes to
   * @fn:	 function to trigger addition of class device.
   *
   * This function allocates storage for the class device(s) to be
   * attached to dev (one for each matching attribute_container).  If no
   * fn is provided, the code will simply register the class device via
ee959b00c   Tony Jones   SCSI: convert str...
126
   * device_add.  If a function is provided, it is expected to add
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
   * the class device at the appropriate time.  One of the things that
   * might be necessary is to allocate and initialise the classdev and
   * then add it a later time.  To do this, call this routine for
   * allocation and initialisation and then use
ee959b00c   Tony Jones   SCSI: convert str...
131
   * attribute_container_device_trigger() to call device_add() on
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
136
137
138
   * it.  Note: after this, the class device contains a reference to dev
   * which is not relinquished until the release of the classdev.
   */
  void
  attribute_container_add_device(struct device *dev,
  			       int (*fn)(struct attribute_container *,
  					 struct device *,
ee959b00c   Tony Jones   SCSI: convert str...
139
  					 struct device *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
  {
  	struct attribute_container *cont;
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
142
  	mutex_lock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
147
148
149
150
  	list_for_each_entry(cont, &attribute_container_list, node) {
  		struct internal_container *ic;
  
  		if (attribute_container_no_classdevs(cont))
  			continue;
  
  		if (!cont->match(cont, dev))
  			continue;
4aed0644d   Jiri Slaby   [PATCH] drivers/b...
151
152
  
  		ic = kzalloc(sizeof(*ic), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  		if (!ic) {
a369a7ebb   Joe Perches   drivers: base: Co...
154
155
  			dev_err(dev, "failed to allocate class container
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
  			continue;
  		}
4aed0644d   Jiri Slaby   [PATCH] drivers/b...
158

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  		ic->cont = cont;
ee959b00c   Tony Jones   SCSI: convert str...
160
161
  		device_initialize(&ic->classdev);
  		ic->classdev.parent = get_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  		ic->classdev.class = cont->class;
ee959b00c   Tony Jones   SCSI: convert str...
163
  		cont->class->dev_release = attribute_container_release;
02aa2a376   Kees Cook   drivers: avoid fo...
164
  		dev_set_name(&ic->classdev, "%s", dev_name(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
168
  		if (fn)
  			fn(cont, dev, &ic->classdev);
  		else
  			attribute_container_add_class_device(&ic->classdev);
53c165e0a   James Bottomley   [SCSI] correct at...
169
  		klist_add_tail(&ic->node, &cont->containers);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  	}
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
171
  	mutex_unlock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  }
53c165e0a   James Bottomley   [SCSI] correct at...
173
174
175
176
177
178
  /* FIXME: can't break out of this unless klist_iter_exit is also
   * called before doing the break
   */
  #define klist_for_each_entry(pos, head, member, iter) \
  	for (klist_iter_init(head, iter); (pos = ({ \
  		struct klist_node *n = klist_next(iter); \
caf39e87c   Linus Torvalds   [SCSI] Re-do "fin...
179
180
  		n ? container_of(n, typeof(*pos), member) : \
  			({ klist_iter_exit(iter) ; NULL; }); \
287f9bd93   Tina Johnson   attribute_contain...
181
  	})) != NULL;)
24a7d36a7   Tina Johnson   attribute_contain...
182

53c165e0a   James Bottomley   [SCSI] correct at...
183

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
190
  /**
   * attribute_container_remove_device - make device eligible for removal.
   *
   * @dev:  The generic device
   * @fn:	  A function to call to remove the device
   *
   * This routine triggers device removal.  If fn is NULL, then it is
ee959b00c   Tony Jones   SCSI: convert str...
191
   * simply done via device_unregister (note that if something
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
   * still has a reference to the classdev, then the memory occupied
   * will not be freed until the classdev is released).  If you want a
   * two phase release: remove from visibility and then delete the
   * device, then you should use this routine with a fn that calls
ee959b00c   Tony Jones   SCSI: convert str...
196
197
   * device_del() and then use attribute_container_device_trigger()
   * to do the final put on the classdev.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
   */
  void
  attribute_container_remove_device(struct device *dev,
  				  void (*fn)(struct attribute_container *,
  					     struct device *,
ee959b00c   Tony Jones   SCSI: convert str...
203
  					     struct device *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
  {
  	struct attribute_container *cont;
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
206
  	mutex_lock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
  	list_for_each_entry(cont, &attribute_container_list, node) {
53c165e0a   James Bottomley   [SCSI] correct at...
208
209
  		struct internal_container *ic;
  		struct klist_iter iter;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
214
215
  
  		if (attribute_container_no_classdevs(cont))
  			continue;
  
  		if (!cont->match(cont, dev))
  			continue;
53c165e0a   James Bottomley   [SCSI] correct at...
216
217
  
  		klist_for_each_entry(ic, &cont->containers, node, &iter) {
ee959b00c   Tony Jones   SCSI: convert str...
218
  			if (dev != ic->classdev.parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  				continue;
caf39e87c   Linus Torvalds   [SCSI] Re-do "fin...
220
  			klist_del(&ic->node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
  			if (fn)
  				fn(cont, dev, &ic->classdev);
  			else {
  				attribute_container_remove_attrs(&ic->classdev);
ee959b00c   Tony Jones   SCSI: convert str...
225
  				device_unregister(&ic->classdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
  			}
  		}
  	}
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
229
  	mutex_unlock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231

7c1ef3387   Gabriel Krisman Bertazi   scsi: drivers: ba...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
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
  static int
  do_attribute_container_device_trigger_safe(struct device *dev,
  					   struct attribute_container *cont,
  					   int (*fn)(struct attribute_container *,
  						     struct device *, struct device *),
  					   int (*undo)(struct attribute_container *,
  						       struct device *, struct device *))
  {
  	int ret;
  	struct internal_container *ic, *failed;
  	struct klist_iter iter;
  
  	if (attribute_container_no_classdevs(cont))
  		return fn(cont, dev, NULL);
  
  	klist_for_each_entry(ic, &cont->containers, node, &iter) {
  		if (dev == ic->classdev.parent) {
  			ret = fn(cont, dev, &ic->classdev);
  			if (ret) {
  				failed = ic;
  				klist_iter_exit(&iter);
  				goto fail;
  			}
  		}
  	}
  	return 0;
  
  fail:
  	if (!undo)
  		return ret;
  
  	/* Attempt to undo the work partially done. */
  	klist_for_each_entry(ic, &cont->containers, node, &iter) {
  		if (ic == failed) {
  			klist_iter_exit(&iter);
  			break;
  		}
  		if (dev == ic->classdev.parent)
  			undo(cont, dev, &ic->classdev);
  	}
  	return ret;
  }
  
  /**
   * attribute_container_device_trigger_safe - execute a trigger for each
   * matching classdev or fail all of them.
   *
   * @dev:  The generic device to run the trigger for
   * @fn	  the function to execute for each classdev.
   * @undo  A function to undo the work previously done in case of error
   *
   * This function is a safe version of
   * attribute_container_device_trigger. It stops on the first error and
   * undo the partial work that has been done, on previous classdev.  It
   * is guaranteed that either they all succeeded, or none of them
   * succeeded.
   */
  int
  attribute_container_device_trigger_safe(struct device *dev,
  					int (*fn)(struct attribute_container *,
  						  struct device *,
  						  struct device *),
  					int (*undo)(struct attribute_container *,
  						    struct device *,
  						    struct device *))
  {
  	struct attribute_container *cont, *failed = NULL;
  	int ret = 0;
  
  	mutex_lock(&attribute_container_mutex);
  
  	list_for_each_entry(cont, &attribute_container_list, node) {
  
  		if (!cont->match(cont, dev))
  			continue;
  
  		ret = do_attribute_container_device_trigger_safe(dev, cont,
  								 fn, undo);
  		if (ret) {
  			failed = cont;
  			break;
  		}
  	}
  
  	if (ret && !WARN_ON(!undo)) {
  		list_for_each_entry(cont, &attribute_container_list, node) {
  
  			if (failed == cont)
  				break;
  
  			if (!cont->match(cont, dev))
  				continue;
  
  			do_attribute_container_device_trigger_safe(dev, cont,
  								   undo, NULL);
  		}
  	}
  
  	mutex_unlock(&attribute_container_mutex);
  	return ret;
  
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
338
339
  /**
   * attribute_container_device_trigger - execute a trigger for each matching classdev
   *
   * @dev:  The generic device to run the trigger for
   * @fn	  the function to execute for each classdev.
   *
03aca7b26   Xiubo Li   attribute_contain...
340
   * This function is for executing a trigger when you need to know both
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
344
   * the container and the classdev.  If you only care about the
   * container, then use attribute_container_trigger() instead.
   */
  void
24a7d36a7   Tina Johnson   attribute_contain...
345
  attribute_container_device_trigger(struct device *dev,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
  				   int (*fn)(struct attribute_container *,
  					     struct device *,
ee959b00c   Tony Jones   SCSI: convert str...
348
  					     struct device *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
  {
  	struct attribute_container *cont;
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
351
  	mutex_lock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  	list_for_each_entry(cont, &attribute_container_list, node) {
53c165e0a   James Bottomley   [SCSI] correct at...
353
354
  		struct internal_container *ic;
  		struct klist_iter iter;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
  
  		if (!cont->match(cont, dev))
  			continue;
ebd8bb764   James Bottomley   [SCSI] fix transp...
358
359
360
361
  		if (attribute_container_no_classdevs(cont)) {
  			fn(cont, dev, NULL);
  			continue;
  		}
53c165e0a   James Bottomley   [SCSI] correct at...
362
  		klist_for_each_entry(ic, &cont->containers, node, &iter) {
ee959b00c   Tony Jones   SCSI: convert str...
363
  			if (dev == ic->classdev.parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
  				fn(cont, dev, &ic->classdev);
  		}
  	}
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
367
  	mutex_unlock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
  
  /**
   * attribute_container_trigger - trigger a function for each matching container
   *
   * @dev:  The generic device to activate the trigger for
   * @fn:	  the function to trigger
   *
   * This routine triggers a function that only needs to know the
   * matching containers (not the classdev) associated with a device.
   * It is more lightweight than attribute_container_device_trigger, so
   * should be used in preference unless the triggering function
   * actually needs to know the classdev.
   */
  void
  attribute_container_trigger(struct device *dev,
  			    int (*fn)(struct attribute_container *,
  				      struct device *))
  {
  	struct attribute_container *cont;
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
388
  	mutex_lock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
392
  	list_for_each_entry(cont, &attribute_container_list, node) {
  		if (cont->match(cont, dev))
  			fn(cont, dev);
  	}
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
393
  	mutex_unlock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
399
400
401
402
403
404
  
  /**
   * attribute_container_add_attrs - add attributes
   *
   * @classdev: The class device
   *
   * This simply creates all the class device sysfs files from the
   * attributes listed in the container
   */
  int
ee959b00c   Tony Jones   SCSI: convert str...
405
  attribute_container_add_attrs(struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
  {
  	struct attribute_container *cont =
  		attribute_container_classdev_to_container(classdev);
ee959b00c   Tony Jones   SCSI: convert str...
409
  	struct device_attribute **attrs = cont->attrs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
  	int i, error;
fd1109711   James Bottomley   [SCSI] attribute_...
411
412
413
  	BUG_ON(attrs && cont->grp);
  
  	if (!attrs && !cont->grp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
  		return 0;
fd1109711   James Bottomley   [SCSI] attribute_...
415
416
  	if (cont->grp)
  		return sysfs_create_group(&classdev->kobj, cont->grp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
  	for (i = 0; attrs[i]; i++) {
ebd09ec93   James Bottomley   [SCSI] attirbute_...
418
  		sysfs_attr_init(&attrs[i]->attr);
ee959b00c   Tony Jones   SCSI: convert str...
419
  		error = device_create_file(classdev, attrs[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
423
424
425
  		if (error)
  			return error;
  	}
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
  
  /**
ee959b00c   Tony Jones   SCSI: convert str...
428
   * attribute_container_add_class_device - same function as device_add
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
   *
   * @classdev:	the class device to add
   *
ee959b00c   Tony Jones   SCSI: convert str...
432
   * This performs essentially the same function as device_add except for
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
436
   * attribute containers, namely add the classdev to the system and then
   * create the attribute files
   */
  int
ee959b00c   Tony Jones   SCSI: convert str...
437
  attribute_container_add_class_device(struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
  {
ee959b00c   Tony Jones   SCSI: convert str...
439
  	int error = device_add(classdev);
481026dbe   Cosmin Dragomir   attribute_contain...
440

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
  	if (error)
  		return error;
  	return attribute_container_add_attrs(classdev);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
449
450
451
452
453
454
  
  /**
   * attribute_container_add_class_device_adapter - simple adapter for triggers
   *
   * This function is identical to attribute_container_add_class_device except
   * that it is designed to be called from the triggers
   */
  int
  attribute_container_add_class_device_adapter(struct attribute_container *cont,
  					     struct device *dev,
ee959b00c   Tony Jones   SCSI: convert str...
455
  					     struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
458
  {
  	return attribute_container_add_class_device(classdev);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
461
462
463
464
465
466
  
  /**
   * attribute_container_remove_attrs - remove any attribute files
   *
   * @classdev: The class device to remove the files from
   *
   */
  void
ee959b00c   Tony Jones   SCSI: convert str...
467
  attribute_container_remove_attrs(struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
470
  {
  	struct attribute_container *cont =
  		attribute_container_classdev_to_container(classdev);
ee959b00c   Tony Jones   SCSI: convert str...
471
  	struct device_attribute **attrs = cont->attrs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  	int i;
fd1109711   James Bottomley   [SCSI] attribute_...
473
  	if (!attrs && !cont->grp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  		return;
fd1109711   James Bottomley   [SCSI] attribute_...
475
476
477
478
  	if (cont->grp) {
  		sysfs_remove_group(&classdev->kobj, cont->grp);
  		return ;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  	for (i = 0; attrs[i]; i++)
ee959b00c   Tony Jones   SCSI: convert str...
480
  		device_remove_file(classdev, attrs[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
485
486
487
488
  
  /**
   * attribute_container_class_device_del - equivalent of class_device_del
   *
   * @classdev: the class device
   *
   * This function simply removes all the attribute files and then calls
ee959b00c   Tony Jones   SCSI: convert str...
489
   * device_del.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
   */
  void
ee959b00c   Tony Jones   SCSI: convert str...
492
  attribute_container_class_device_del(struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
  {
  	attribute_container_remove_attrs(classdev);
ee959b00c   Tony Jones   SCSI: convert str...
495
  	device_del(classdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497

d0a7e5740   James Bottomley   [SCSI] correct tr...
498
499
500
501
502
503
504
505
506
  /**
   * attribute_container_find_class_device - find the corresponding class_device
   *
   * @cont:	the container
   * @dev:	the generic device
   *
   * Looks up the device in the container's list of class devices and returns
   * the corresponding class_device.
   */
ee959b00c   Tony Jones   SCSI: convert str...
507
  struct device *
d0a7e5740   James Bottomley   [SCSI] correct tr...
508
509
510
  attribute_container_find_class_device(struct attribute_container *cont,
  				      struct device *dev)
  {
ee959b00c   Tony Jones   SCSI: convert str...
511
  	struct device *cdev = NULL;
d0a7e5740   James Bottomley   [SCSI] correct tr...
512
  	struct internal_container *ic;
53c165e0a   James Bottomley   [SCSI] correct at...
513
  	struct klist_iter iter;
d0a7e5740   James Bottomley   [SCSI] correct tr...
514

53c165e0a   James Bottomley   [SCSI] correct at...
515
  	klist_for_each_entry(ic, &cont->containers, node, &iter) {
ee959b00c   Tony Jones   SCSI: convert str...
516
  		if (ic->classdev.parent == dev) {
d0a7e5740   James Bottomley   [SCSI] correct tr...
517
  			cdev = &ic->classdev;
53c165e0a   James Bottomley   [SCSI] correct at...
518
519
  			/* FIXME: must exit iterator then break */
  			klist_iter_exit(&iter);
d0a7e5740   James Bottomley   [SCSI] correct tr...
520
521
522
  			break;
  		}
  	}
d0a7e5740   James Bottomley   [SCSI] correct tr...
523
524
525
526
  
  	return cdev;
  }
  EXPORT_SYMBOL_GPL(attribute_container_find_class_device);