drivers/counter/counter-core.c

Source file repositories/reference/linux-study-clean/drivers/counter/counter-core.c

File Facts

System
Linux kernel
Corpus path
drivers/counter/counter-core.c
Extension
.c
Size
6553 bytes
Lines
285
Domain
Driver Families
Bucket
drivers/counter
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 const struct bus_type counter_bus_type = {
	.name = "counter",
	.dev_name = "counter",
};

static dev_t counter_devt;

/**
 * counter_priv - access counter device private data
 * @counter: counter device
 *
 * Get the counter device private data
 */
void *counter_priv(const struct counter_device *const counter)
{
	struct counter_device_allochelper *ch =
		container_of(counter, struct counter_device_allochelper, counter);

	return &ch->privdata;
}
EXPORT_SYMBOL_NS_GPL(counter_priv, "COUNTER");

/**
 * counter_alloc - allocate a counter_device
 * @sizeof_priv: size of the driver private data
 *
 * This is part one of counter registration. The structure is allocated
 * dynamically to ensure the right lifetime for the embedded struct device.
 *
 * If this succeeds, call counter_put() to get rid of the counter_device again.
 */
struct counter_device *counter_alloc(size_t sizeof_priv)
{
	struct counter_device_allochelper *ch;
	struct counter_device *counter;
	struct device *dev;
	int err;

	ch = kzalloc(sizeof(*ch) + sizeof_priv, GFP_KERNEL);
	if (!ch)
		return NULL;

	counter = &ch->counter;
	dev = &counter->dev;

	/* Acquire unique ID */
	err = ida_alloc(&counter_ida, GFP_KERNEL);
	if (err < 0)
		goto err_ida_alloc;
	dev->id = err;

	mutex_init(&counter->ops_exist_lock);
	dev->type = &counter_device_type;
	dev->bus = &counter_bus_type;
	dev->devt = MKDEV(MAJOR(counter_devt), dev->id);

	err = counter_chrdev_add(counter);
	if (err < 0)
		goto err_chrdev_add;

	device_initialize(dev);

	err = dev_set_name(dev, COUNTER_NAME "%d", dev->id);
	if (err)
		goto err_dev_set_name;

	return counter;

err_dev_set_name:

	put_device(dev);
	return NULL;
err_chrdev_add:

	ida_free(&counter_ida, dev->id);
err_ida_alloc:

	kfree(ch);

	return NULL;
}
EXPORT_SYMBOL_NS_GPL(counter_alloc, "COUNTER");

void counter_put(struct counter_device *counter)
{
	put_device(&counter->dev);
}
EXPORT_SYMBOL_NS_GPL(counter_put, "COUNTER");

/**

Annotation

Implementation Notes