drivers/base/attribute_container.c

Source file repositories/reference/linux-study-clean/drivers/base/attribute_container.c

File Facts

System
Linux kernel
Corpus path
drivers/base/attribute_container.c
Extension
.c
Size
13323 bytes
Lines
501
Domain
Driver Families
Bucket
drivers/base
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

* device_add.  If a function is provided, it is expected to add
 * 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
 * attribute_container_device_trigger() to call device_add() on
 * 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 *,
					 struct device *))
{
	struct attribute_container *cont;

	mutex_lock(&attribute_container_mutex);
	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;

		ic = kzalloc_obj(*ic);
		if (!ic) {
			dev_err(dev, "failed to allocate class container\n");
			continue;
		}

		ic->cont = cont;
		device_initialize(&ic->classdev);
		ic->classdev.parent = get_device(dev);
		ic->classdev.class = cont->class;
		cont->class->dev_release = attribute_container_release;
		dev_set_name(&ic->classdev, "%s", dev_name(dev));
		if (fn)
			fn(cont, dev, &ic->classdev);
		else
			attribute_container_add_class_device(&ic->classdev);
		klist_add_tail(&ic->node, &cont->containers);
	}
	mutex_unlock(&attribute_container_mutex);
}

/* 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); \
		n ? container_of(n, typeof(*pos), member) : \
			({ klist_iter_exit(iter) ; NULL; }); \
	})) != NULL;)


/**
 * 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
 * simply done via device_unregister (note that if something
 * 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
 * device_del() and then use attribute_container_device_trigger()
 * to do the final put on the classdev.
 */
void
attribute_container_remove_device(struct device *dev,
				  void (*fn)(struct attribute_container *,
					     struct device *,
					     struct device *))
{
	struct attribute_container *cont;

	mutex_lock(&attribute_container_mutex);
	list_for_each_entry(cont, &attribute_container_list, node) {
		struct internal_container *ic;
		struct klist_iter iter;

		if (attribute_container_no_classdevs(cont))
			continue;

Annotation

Implementation Notes