drivers/char/ppdev.c

Source file repositories/reference/linux-study-clean/drivers/char/ppdev.c

File Facts

System
Linux kernel
Corpus path
drivers/char/ppdev.c
Extension
.c
Size
20825 bytes
Lines
886
Domain
Driver Families
Bucket
drivers/char
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 pp_fops = {
	.owner		= THIS_MODULE,
	.read		= pp_read,
	.write		= pp_write,
	.poll		= pp_poll,
	.unlocked_ioctl	= pp_ioctl,
	.compat_ioctl   = compat_ptr_ioctl,
	.open		= pp_open,
	.release	= pp_release,
};

static void pp_attach(struct parport *port)
{
	struct device *ret;

	if (devices[port->number])
		return;

	ret = device_create(&ppdev_class, port->dev,
			    MKDEV(PP_MAJOR, port->number), NULL,
			    "parport%d", port->number);
	if (IS_ERR(ret)) {
		pr_err("Failed to create device parport%d\n",
		       port->number);
		return;
	}
	devices[port->number] = ret;
}

static void pp_detach(struct parport *port)
{
	if (!devices[port->number])
		return;

	device_destroy(&ppdev_class, MKDEV(PP_MAJOR, port->number));
	devices[port->number] = NULL;
}

static int pp_probe(struct pardevice *par_dev)
{
	struct device_driver *drv = par_dev->dev.driver;
	int len = strlen(drv->name);

	if (strncmp(par_dev->name, drv->name, len))
		return -ENODEV;

	return 0;
}

static struct parport_driver pp_driver = {
	.name		= CHRDEV,
	.probe		= pp_probe,
	.match_port	= pp_attach,
	.detach		= pp_detach,
};

static int __init ppdev_init(void)
{
	int err = 0;

	if (register_chrdev(PP_MAJOR, CHRDEV, &pp_fops)) {
		pr_warn(CHRDEV ": unable to get major %d\n", PP_MAJOR);
		return -EIO;
	}
	err = class_register(&ppdev_class);
	if (err)
		goto out_chrdev;

	err = parport_register_driver(&pp_driver);
	if (err < 0) {
		pr_warn(CHRDEV ": unable to register with parport\n");
		goto out_class;
	}

	pr_info(PP_VERSION "\n");
	goto out;

out_class:
	class_unregister(&ppdev_class);
out_chrdev:
	unregister_chrdev(PP_MAJOR, CHRDEV);
out:
	return err;
}

static void __exit ppdev_cleanup(void)
{
	/* Clean up all parport stuff */
	parport_unregister_driver(&pp_driver);
	class_unregister(&ppdev_class);

Annotation

Implementation Notes