drivers/media/cec/core/cec-core.c

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

File Facts

System
Linux kernel
Corpus path
drivers/media/cec/core/cec-core.c
Extension
.c
Size
11417 bytes
Lines
446
Domain
Driver Families
Bucket
drivers/media
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 cec_bus_type = {
	.name = CEC_NAME,
};

/*
 * Register a cec device node
 *
 * The registration code assigns minor numbers and registers the new device node
 * with the kernel. An error is returned if no free minor number can be found,
 * or if the registration of the device node fails.
 *
 * Zero is returned on success.
 *
 * Note that if the cec_devnode_register call fails, the release() callback of
 * the cec_devnode structure is *not* called, so the caller is responsible for
 * freeing any data.
 */
static int __must_check cec_devnode_register(struct cec_devnode *devnode,
					     struct module *owner)
{
	int minor;
	int ret;

	/* Part 1: Find a free minor number */
	mutex_lock(&cec_devnode_lock);
	minor = find_first_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES);
	if (minor == CEC_NUM_DEVICES) {
		mutex_unlock(&cec_devnode_lock);
		pr_err("could not get a free minor\n");
		return -ENFILE;
	}

	set_bit(minor, cec_devnode_nums);
	mutex_unlock(&cec_devnode_lock);

	devnode->minor = minor;
	devnode->dev.bus = &cec_bus_type;
	devnode->dev.devt = MKDEV(MAJOR(cec_dev_t), minor);
	devnode->dev.release = cec_devnode_release;
	dev_set_name(&devnode->dev, "cec%d", devnode->minor);
	device_initialize(&devnode->dev);

	/* Part 2: Initialize and register the character device */
	cdev_init(&devnode->cdev, &cec_devnode_fops);
	devnode->cdev.owner = owner;
	kobject_set_name(&devnode->cdev.kobj, "cec%d", devnode->minor);

	devnode->registered = true;
	ret = cdev_device_add(&devnode->cdev, &devnode->dev);
	if (ret) {
		devnode->registered = false;
		pr_err("%s: cdev_device_add failed\n", __func__);
		goto clr_bit;
	}

	return 0;

clr_bit:
	mutex_lock(&cec_devnode_lock);
	clear_bit(devnode->minor, cec_devnode_nums);
	mutex_unlock(&cec_devnode_lock);
	return ret;
}

/*
 * Unregister a cec device node
 *
 * This unregisters the passed device. Future open calls will be met with
 * errors.
 *
 * This function can safely be called if the device node has never been
 * registered or has already been unregistered.
 */
static void cec_devnode_unregister(struct cec_adapter *adap)
{
	struct cec_devnode *devnode = &adap->devnode;
	struct cec_fh *fh;

	mutex_lock(&devnode->lock);

	/* Check if devnode was never registered or already unregistered */
	if (!devnode->registered || devnode->unregistered) {
		mutex_unlock(&devnode->lock);
		return;
	}
	devnode->registered = false;
	devnode->unregistered = true;

	mutex_lock(&devnode->lock_fhs);
	list_for_each_entry(fh, &devnode->fhs, list)

Annotation

Implementation Notes