drivers/media/rc/lirc_dev.c

Source file repositories/reference/linux-study-clean/drivers/media/rc/lirc_dev.c

File Facts

System
Linux kernel
Corpus path
drivers/media/rc/lirc_dev.c
Extension
.c
Size
18117 bytes
Lines
841
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 file_operations lirc_fops = {
	.owner		= THIS_MODULE,
	.write		= lirc_transmit,
	.unlocked_ioctl	= lirc_ioctl,
	.compat_ioctl	= compat_ptr_ioctl,
	.read		= lirc_read,
	.poll		= lirc_poll,
	.open		= lirc_open,
	.release	= lirc_close,
};

static void lirc_release_device(struct device *ld)
{
	struct rc_dev *rcdev = container_of(ld, struct rc_dev, lirc_dev);

	put_device(&rcdev->dev);
}

int lirc_register(struct rc_dev *dev)
{
	const char *rx_type, *tx_type;
	int err, minor;

	minor = ida_alloc_max(&lirc_ida, RC_DEV_MAX - 1, GFP_KERNEL);
	if (minor < 0)
		return minor;

	device_initialize(&dev->lirc_dev);
	dev->lirc_dev.class = &lirc_class;
	dev->lirc_dev.parent = &dev->dev;
	dev->lirc_dev.release = lirc_release_device;
	dev->lirc_dev.devt = MKDEV(MAJOR(lirc_base_dev), minor);
	dev_set_name(&dev->lirc_dev, "lirc%d", minor);

	INIT_LIST_HEAD(&dev->lirc_fh);
	spin_lock_init(&dev->lirc_fh_lock);

	cdev_init(&dev->lirc_cdev, &lirc_fops);

	get_device(&dev->dev);

	err = cdev_device_add(&dev->lirc_cdev, &dev->lirc_dev);
	if (err)
		goto out_put_device;

	switch (dev->driver_type) {
	case RC_DRIVER_SCANCODE:
		rx_type = "scancode";
		break;
	case RC_DRIVER_IR_RAW:
		rx_type = "raw IR";
		break;
	default:
		rx_type = "no";
		break;
	}

	if (dev->tx_ir)
		tx_type = "raw IR";
	else
		tx_type = "no";

	dev_info(&dev->dev, "lirc_dev: driver %s registered at minor = %d, %s receiver, %s transmitter",
		 dev->driver_name, minor, rx_type, tx_type);

	return 0;

out_put_device:
	put_device(&dev->lirc_dev);
	ida_free(&lirc_ida, minor);
	return err;
}

void lirc_unregister(struct rc_dev *dev)
{
	unsigned long flags;
	struct lirc_fh *fh;

	dev_dbg(&dev->dev, "lirc_dev: driver %s unregistered from minor = %d\n",
		dev->driver_name, MINOR(dev->lirc_dev.devt));

	spin_lock_irqsave(&dev->lirc_fh_lock, flags);
	list_for_each_entry(fh, &dev->lirc_fh, list)
		wake_up_poll(&fh->wait_poll, EPOLLHUP | EPOLLERR);
	spin_unlock_irqrestore(&dev->lirc_fh_lock, flags);

	cdev_device_del(&dev->lirc_cdev, &dev->lirc_dev);
	ida_free(&lirc_ida, MINOR(dev->lirc_dev.devt));
}

Annotation

Implementation Notes