drivers/pps/generators/pps_gen.c

Source file repositories/reference/linux-study-clean/drivers/pps/generators/pps_gen.c

File Facts

System
Linux kernel
Corpus path
drivers/pps/generators/pps_gen.c
Extension
.c
Size
7844 bytes
Lines
347
Domain
Driver Families
Bucket
drivers/pps
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 file_operations pps_gen_cdev_fops = {
	.owner		= THIS_MODULE,
	.poll	   = pps_gen_cdev_poll,
	.fasync	 = pps_gen_cdev_fasync,
	.unlocked_ioctl	= pps_gen_cdev_ioctl,
	.open		= pps_gen_cdev_open,
	.release	= pps_gen_cdev_release,
};

static void pps_gen_device_destruct(struct device *dev)
{
	struct pps_gen_device *pps_gen = dev_get_drvdata(dev);

	cdev_del(&pps_gen->cdev);

	pr_debug("deallocating pps-gen%d\n", pps_gen->id);
	ida_free(&pps_gen_ida, pps_gen->id);

	kfree(dev);
	kfree(pps_gen);
}

static int pps_gen_register_cdev(struct pps_gen_device *pps_gen)
{
	int err;
	dev_t devt;

	err = ida_alloc_max(&pps_gen_ida, PPS_GEN_MAX_SOURCES - 1, GFP_KERNEL);
	if (err < 0) {
		if (err == -ENOSPC) {
			pr_err("too many PPS sources in the system\n");
			err = -EBUSY;
		}
		return err;
	}
	pps_gen->id = err;

	devt = MKDEV(MAJOR(pps_gen_devt), pps_gen->id);

	cdev_init(&pps_gen->cdev, &pps_gen_cdev_fops);
	pps_gen->cdev.owner = pps_gen->info->owner;

	err = cdev_add(&pps_gen->cdev, devt, 1);
	if (err) {
		pr_err("failed to add char device %d:%d\n",
				MAJOR(pps_gen_devt), pps_gen->id);
		goto free_ida;
	}
	pps_gen->dev = device_create(&pps_gen_class, pps_gen->info->parent, devt,
				     pps_gen, "pps-gen%d", pps_gen->id);
	if (IS_ERR(pps_gen->dev)) {
		err = PTR_ERR(pps_gen->dev);
		goto del_cdev;
	}
	pps_gen->dev->release = pps_gen_device_destruct;
	dev_set_drvdata(pps_gen->dev, pps_gen);

	pr_debug("generator got cdev (%d:%d)\n",
			MAJOR(pps_gen_devt), pps_gen->id);

	return 0;

del_cdev:
	cdev_del(&pps_gen->cdev);
free_ida:
	ida_free(&pps_gen_ida, pps_gen->id);
	return err;
}

static void pps_gen_unregister_cdev(struct pps_gen_device *pps_gen)
{
	pr_debug("unregistering pps-gen%d\n", pps_gen->id);
	device_destroy(&pps_gen_class, pps_gen->dev->devt);
}

/*
 * Exported functions
 */

/**
 * pps_gen_register_source() - add a PPS generator in the system
 * @info: the PPS generator info struct
 *
 * This function is used to register a new PPS generator in the system.
 * When it returns successfully the new generator is up and running, and
 * it can be managed by the userspace.
 *
 * Return: the PPS generator device in case of success, and ERR_PTR(errno)
 *	 otherwise.
 */

Annotation

Implementation Notes