drivers/input/serio/serio_raw.c

Source file repositories/reference/linux-study-clean/drivers/input/serio/serio_raw.c

File Facts

System
Linux kernel
Corpus path
drivers/input/serio/serio_raw.c
Extension
.c
Size
9592 bytes
Lines
419
Domain
Driver Families
Bucket
drivers/input
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 serio_raw_fops = {
	.owner		= THIS_MODULE,
	.open		= serio_raw_open,
	.release	= serio_raw_release,
	.read		= serio_raw_read,
	.write		= serio_raw_write,
	.poll		= serio_raw_poll,
	.fasync		= serio_raw_fasync,
	.llseek		= noop_llseek,
};


/*********************************************************************
 *                   Interface with serio port                       *
 *********************************************************************/

static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
					unsigned int dfl)
{
	struct serio_raw *serio_raw = serio_get_drvdata(serio);
	struct serio_raw_client *client;
	unsigned int head = serio_raw->head;

	/* we are holding serio->lock here so we are protected */
	serio_raw->queue[head] = data;
	head = (head + 1) % SERIO_RAW_QUEUE_LEN;
	if (likely(head != serio_raw->tail)) {
		serio_raw->head = head;
		list_for_each_entry(client, &serio_raw->client_list, node)
			kill_fasync(&client->fasync, SIGIO, POLL_IN);
		wake_up_interruptible(&serio_raw->wait);
	}

	return IRQ_HANDLED;
}

static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
{
	static atomic_t serio_raw_no = ATOMIC_INIT(-1);
	struct serio_raw *serio_raw;
	int err;

	serio_raw = kzalloc_obj(*serio_raw);
	if (!serio_raw) {
		dev_dbg(&serio->dev, "can't allocate memory for a device\n");
		return -ENOMEM;
	}

	snprintf(serio_raw->name, sizeof(serio_raw->name),
		 "serio_raw%u", atomic_inc_return(&serio_raw_no));
	kref_init(&serio_raw->kref);
	INIT_LIST_HEAD(&serio_raw->client_list);
	init_waitqueue_head(&serio_raw->wait);

	serio_raw->serio = serio;
	get_device(&serio->dev);

	serio_set_drvdata(serio, serio_raw);

	err = serio_open(serio, drv);
	if (err)
		goto err_free;

	err = mutex_lock_killable(&serio_raw_mutex);
	if (err)
		goto err_close;

	list_add_tail(&serio_raw->node, &serio_raw_list);
	mutex_unlock(&serio_raw_mutex);

	serio_raw->dev.minor = PSMOUSE_MINOR;
	serio_raw->dev.name = serio_raw->name;
	serio_raw->dev.parent = &serio->dev;
	serio_raw->dev.fops = &serio_raw_fops;

	err = misc_register(&serio_raw->dev);
	if (err) {
		serio_raw->dev.minor = MISC_DYNAMIC_MINOR;
		err = misc_register(&serio_raw->dev);
	}

	if (err) {
		dev_err(&serio->dev,
			"failed to register raw access device for %s\n",
			serio->phys);
		goto err_unlink;
	}

	dev_info(&serio->dev, "raw access enabled on %s (%s, minor %d)\n",
		 serio->phys, serio_raw->name, serio_raw->dev.minor);

Annotation

Implementation Notes