drivers/mtd/mtd_virt_concat.c

Source file repositories/reference/linux-study-clean/drivers/mtd/mtd_virt_concat.c

File Facts

System
Linux kernel
Corpus path
drivers/mtd/mtd_virt_concat.c
Extension
.c
Size
8245 bytes
Lines
351
Domain
Driver Families
Bucket
drivers/mtd
Inferred role
Driver Families: implementation source
Status
source 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

struct mtd_virt_concat_node {
	struct list_head head;
	unsigned int count;
	struct mtd_concat *concat;
	struct device_node *nodes[] __counted_by(count);
};

/**
 * mtd_is_part_concat - Check if the device is already part
 *                       of a concatenated device
 * @dev:        pointer to 'device_node'
 *
 * Return: true if the device is already part of a concatenation,
 *         false otherwise.
 */
static bool mtd_is_part_concat(struct device_node *dev)
{
	struct mtd_virt_concat_node *item;
	int idx;

	list_for_each_entry(item, &concat_node_list, head) {
		for (idx = 0; idx < item->count; idx++) {
			if (item->nodes[idx] == dev)
				return true;
		}
	}
	return false;
}

static void mtd_virt_concat_put_mtd_devices(struct mtd_concat *concat)
{
	int i;

	for (i = 0; i < concat->num_subdev; i++)
		put_mtd_device(concat->subdev[i]);
}

void mtd_virt_concat_destroy_joins(void)
{
	struct mtd_virt_concat_node *item, *tmp;
	struct mtd_info *mtd;

	list_for_each_entry_safe(item, tmp, &concat_node_list, head) {
		mtd = &item->concat->mtd;
		if (item->concat) {
			mtd_device_unregister(mtd);
			kfree(mtd->name);
			mtd_concat_destroy(mtd);
			mtd_virt_concat_put_mtd_devices(item->concat);
		}
	}
}

/**
 * mtd_virt_concat_destroy - Destroy the concat that includes the mtd object
 * @mtd:        pointer to 'mtd_info'
 *
 * Return: 0 on success, -error otherwise.
 */
int mtd_virt_concat_destroy(struct mtd_info *mtd)
{
	struct mtd_info *child, *master = mtd_get_master(mtd);
	struct mtd_virt_concat_node *item, *tmp;
	struct mtd_concat *concat;
	int idx, ret = 0;
	bool is_mtd_found;

	list_for_each_entry_safe(item, tmp, &concat_node_list, head) {
		is_mtd_found = false;

		/* Find the concat item that hold the mtd device */
		for (idx = 0; idx < item->count; idx++) {
			if (item->nodes[idx] == mtd->dev.of_node) {
				is_mtd_found = true;
				break;
			}
		}
		if (!is_mtd_found)
			continue;
		concat = item->concat;

		/*
		 * Since this concatenated device is being removed, retrieve
		 * all MTD devices that are part of it and register them
		 * individually.
		 */
		for (idx = 0; idx < concat->num_subdev; idx++) {
			child = concat->subdev[idx];
			if (child->dev.of_node != mtd->dev.of_node) {
				ret = add_mtd_device(child);

Annotation

Implementation Notes