drivers/input/mousedev.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/mousedev.c
Extension
.c
Size
26214 bytes
Lines
1126
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 mousedev_fops = {
	.owner		= THIS_MODULE,
	.read		= mousedev_read,
	.write		= mousedev_write,
	.poll		= mousedev_poll,
	.open		= mousedev_open,
	.release	= mousedev_release,
	.fasync		= mousedev_fasync,
	.llseek		= noop_llseek,
};

/*
 * Mark device non-existent. This disables writes, ioctls and
 * prevents new users from opening the device. Already posted
 * blocking reads will stay, however new ones will fail.
 */
static void mousedev_mark_dead(struct mousedev *mousedev)
{
	mutex_lock(&mousedev->mutex);
	mousedev->exist = false;
	mutex_unlock(&mousedev->mutex);
}

/*
 * Wake up users waiting for IO so they can disconnect from
 * dead device.
 */
static void mousedev_hangup(struct mousedev *mousedev)
{
	struct mousedev_client *client;

	spin_lock(&mousedev->client_lock);
	list_for_each_entry(client, &mousedev->client_list, node)
		kill_fasync(&client->fasync, SIGIO, POLL_HUP);
	spin_unlock(&mousedev->client_lock);

	wake_up_interruptible(&mousedev->wait);
}

static void mousedev_cleanup(struct mousedev *mousedev)
{
	struct input_handle *handle = &mousedev->handle;

	mousedev_mark_dead(mousedev);
	mousedev_hangup(mousedev);

	/* mousedev is marked dead so no one else accesses mousedev->open */
	if (mousedev->open)
		input_close_device(handle);
}

static int mousedev_reserve_minor(bool mixdev)
{
	int minor;

	if (mixdev) {
		minor = input_get_new_minor(MOUSEDEV_MIX, 1, false);
		if (minor < 0)
			pr_err("failed to reserve mixdev minor: %d\n", minor);
	} else {
		minor = input_get_new_minor(MOUSEDEV_MINOR_BASE,
					    MOUSEDEV_MINORS, true);
		if (minor < 0)
			pr_err("failed to reserve new minor: %d\n", minor);
	}

	return minor;
}

static struct mousedev *mousedev_create(struct input_dev *dev,
					struct input_handler *handler,
					bool mixdev)
{
	struct mousedev *mousedev;
	int minor;
	int error;

	minor = mousedev_reserve_minor(mixdev);
	if (minor < 0) {
		error = minor;
		goto err_out;
	}

	mousedev = kzalloc_obj(struct mousedev);
	if (!mousedev) {
		error = -ENOMEM;
		goto err_free_minor;
	}

	INIT_LIST_HEAD(&mousedev->client_list);

Annotation

Implementation Notes