drivers/gpio/gpio-aggregator.c

Source file repositories/reference/linux-study-clean/drivers/gpio/gpio-aggregator.c

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-aggregator.c
Extension
.c
Size
45461 bytes
Lines
1739
Domain
Driver Families
Bucket
drivers/gpio
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static ssize_t gpio_aggregator_new_device_store(struct device_driver *driver,
						const char *buf, size_t count)
{
	struct gpio_aggregator_pdev_meta meta = { .init_via_sysfs = true };
	char name[CONFIGFS_ITEM_NAME_LEN];
	struct gpio_aggregator *aggr;
	struct platform_device *pdev;
	int res;

	if (!try_module_get(THIS_MODULE))
		return -ENOENT;

	/* kernfs guarantees string termination, so count + 1 is safe */
	res = gpio_aggregator_alloc(&aggr, count + 1);
	if (res)
		goto put_module;

	memcpy(aggr->args, buf, count + 1);

	aggr->init_via_sysfs = true;
	aggr->lookups = kzalloc_flex(*aggr->lookups, table, 1);
	if (!aggr->lookups) {
		res = -ENOMEM;
		goto free_ga;
	}

	aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, aggr->id);
	if (!aggr->lookups->dev_id) {
		res = -ENOMEM;
		goto free_table;
	}

	scnprintf(name, sizeof(name), "%s.%d", AGGREGATOR_LEGACY_PREFIX, aggr->id);
	config_group_init_type_name(&aggr->group, name, &gpio_aggregator_device_type);

	/* Expose to configfs */
	res = configfs_register_group(&gpio_aggregator_subsys.su_group,
				      &aggr->group);
	if (res)
		goto free_dev_id;

	res = gpio_aggregator_parse(aggr);
	if (res)
		goto unregister_group;

	gpiod_add_lookup_table(aggr->lookups);

	pdev = platform_device_register_data(NULL, DRV_NAME, aggr->id, &meta, sizeof(meta));
	if (IS_ERR(pdev)) {
		res = PTR_ERR(pdev);
		goto remove_table;
	}

	aggr->pdev = pdev;
	module_put(THIS_MODULE);
	return count;

remove_table:
	gpiod_remove_lookup_table(aggr->lookups);
unregister_group:
	configfs_unregister_group(&aggr->group);
free_dev_id:
	kfree(aggr->lookups->dev_id);
free_table:
	kfree(aggr->lookups);
free_ga:
	gpio_aggregator_free(aggr);
put_module:
	module_put(THIS_MODULE);
	return res;
}

static struct driver_attribute driver_attr_gpio_aggregator_new_device =
	__ATTR(new_device, 0200, NULL, gpio_aggregator_new_device_store);

static void gpio_aggregator_destroy(struct gpio_aggregator *aggr)
{
	scoped_guard(mutex, &aggr->lock) {
		if (gpio_aggregator_is_activating(aggr) ||
		    gpio_aggregator_is_active(aggr))
			gpio_aggregator_deactivate(aggr);
	}
	gpio_aggregator_free_lines(aggr);
	configfs_unregister_group(&aggr->group);
	kfree(aggr);
}

static ssize_t gpio_aggregator_delete_device_store(struct device_driver *driver,
						   const char *buf, size_t count)
{

Annotation

Implementation Notes