1482 lines · 33.2 KB · C
RawDownload
/* * Event char devices, giving access to raw input device events. * * Copyright (c) 1999-2002 Vojtech Pavlik * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define EVDEV_MINOR_BASE	64#define EVDEV_MINORS		32#define EVDEV_MIN_BUFFER_SIZE	64U#define EVDEV_BUF_PACKETS	8 #include <linux/poll.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/init.h>#include <linux/input/mt.h>#include <linux/major.h>#include <linux/device.h>#include <linux/cdev.h>#include "input-compat.h" enum evdev_clock_type {	EV_CLK_REAL = 0,	EV_CLK_MONO,	EV_CLK_BOOT,	EV_CLK_MAX}; struct evdev {	int open;	struct input_handle handle;	wait_queue_head_t wait;	struct evdev_client __rcu *grab;	struct list_head client_list;	spinlock_t client_lock; /* protects client_list */	struct mutex mutex;	struct device dev;	struct cdev cdev;	bool exist;}; struct evdev_client {	unsigned int head;	unsigned int tail;	unsigned int packet_head; /* [future] position of the first element of next packet */	spinlock_t buffer_lock; /* protects access to buffer, head and tail */	struct fasync_struct *fasync;	struct evdev *evdev;	struct list_head node;	unsigned int clk_type;	bool revoked;	unsigned long *evmasks[EV_CNT];	unsigned int bufsize;	struct input_event buffer[];}; static size_t evdev_get_mask_cnt(unsigned int type){	static const size_t counts[EV_CNT] = {		/* EV_SYN==0 is EV_CNT, _not_ SYN_CNT, see EVIOCGBIT */		[EV_SYN]	= EV_CNT,		[EV_KEY]	= KEY_CNT,		[EV_REL]	= REL_CNT,		[EV_ABS]	= ABS_CNT,		[EV_MSC]	= MSC_CNT,		[EV_SW]		= SW_CNT,		[EV_LED]	= LED_CNT,		[EV_SND]	= SND_CNT,		[EV_FF]		= FF_CNT,	}; 	return (type < EV_CNT) ? counts[type] : 0;} /* requires the buffer lock to be held */static bool __evdev_is_filtered(struct evdev_client *client,				unsigned int type,				unsigned int code){	unsigned long *mask;	size_t cnt; 	/* EV_SYN and unknown codes are never filtered */	if (type == EV_SYN || type >= EV_CNT)		return false; 	/* first test whether the type is filtered */	mask = client->evmasks[0];	if (mask && !test_bit(type, mask))		return true; 	/* unknown values are never filtered */	cnt = evdev_get_mask_cnt(type);	if (!cnt || code >= cnt)		return false; 	mask = client->evmasks[type];	return mask && !test_bit(code, mask);} /* flush queued events of type @type, caller must hold client->buffer_lock */static void __evdev_flush_queue(struct evdev_client *client, unsigned int type){	unsigned int i, head, num;	unsigned int mask = client->bufsize - 1;	bool is_report;	struct input_event *ev; 	BUG_ON(type == EV_SYN); 	head = client->tail;	client->packet_head = client->tail; 	/* init to 1 so a leading SYN_REPORT will not be dropped */	num = 1; 	for (i = client->tail; i != client->head; i = (i + 1) & mask) {		ev = &client->buffer[i];		is_report = ev->type == EV_SYN && ev->code == SYN_REPORT; 		if (ev->type == type) {			/* drop matched entry */			continue;		} else if (is_report && !num) {			/* drop empty SYN_REPORT groups */			continue;		} else if (head != i) {			/* move entry to fill the gap */			client->buffer[head] = *ev;		} 		num++;		head = (head + 1) & mask; 		if (is_report) {			num = 0;			client->packet_head = head;		}	} 	client->head = head;} static void __evdev_queue_syn_dropped(struct evdev_client *client){	struct input_event ev;	ktime_t time;	struct timespec64 ts; 	time = client->clk_type == EV_CLK_REAL ?			ktime_get_real() :			client->clk_type == EV_CLK_MONO ?				ktime_get() :				ktime_get_boottime(); 	ts = ktime_to_timespec64(time);	ev.input_event_sec = ts.tv_sec;	ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;	ev.type = EV_SYN;	ev.code = SYN_DROPPED;	ev.value = 0; 	client->buffer[client->head++] = ev;	client->head &= client->bufsize - 1; 	if (unlikely(client->head == client->tail)) {		/* drop queue but keep our SYN_DROPPED event */		client->tail = (client->head - 1) & (client->bufsize - 1);		client->packet_head = client->tail;	}} static void evdev_queue_syn_dropped(struct evdev_client *client){	unsigned long flags; 	spin_lock_irqsave(&client->buffer_lock, flags);	__evdev_queue_syn_dropped(client);	spin_unlock_irqrestore(&client->buffer_lock, flags);} static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid){	unsigned long flags;	unsigned int clk_type; 	switch (clkid) { 	case CLOCK_REALTIME:		clk_type = EV_CLK_REAL;		break;	case CLOCK_MONOTONIC:		clk_type = EV_CLK_MONO;		break;	case CLOCK_BOOTTIME:		clk_type = EV_CLK_BOOT;		break;	default:		return -EINVAL;	} 	if (client->clk_type != clk_type) {		client->clk_type = clk_type; 		/*		 * Flush pending events and queue SYN_DROPPED event,		 * but only if the queue is not empty.		 */		spin_lock_irqsave(&client->buffer_lock, flags); 		if (client->head != client->tail) {			client->packet_head = client->head = client->tail;			__evdev_queue_syn_dropped(client);		} 		spin_unlock_irqrestore(&client->buffer_lock, flags);	} 	return 0;} static void __pass_event(struct evdev_client *client,			 const struct input_event *event){	client->buffer[client->head++] = *event;	client->head &= client->bufsize - 1; 	if (unlikely(client->head == client->tail)) {		/*		 * This effectively "drops" all unconsumed events, leaving		 * EV_SYN/SYN_DROPPED plus the newest event in the queue.		 */		client->tail = (client->head - 2) & (client->bufsize - 1); 		client->buffer[client->tail].input_event_sec =						event->input_event_sec;		client->buffer[client->tail].input_event_usec =						event->input_event_usec;		client->buffer[client->tail].type = EV_SYN;		client->buffer[client->tail].code = SYN_DROPPED;		client->buffer[client->tail].value = 0; 		client->packet_head = client->tail;	} 	if (event->type == EV_SYN && event->code == SYN_REPORT) {		client->packet_head = client->head;		kill_fasync(&client->fasync, SIGIO, POLL_IN);	}} static void evdev_pass_values(struct evdev_client *client,			const struct input_value *vals, unsigned int count,			ktime_t *ev_time){	struct evdev *evdev = client->evdev;	const struct input_value *v;	struct input_event event;	struct timespec64 ts;	bool wakeup = false; 	if (client->revoked)		return; 	ts = ktime_to_timespec64(ev_time[client->clk_type]);	event.input_event_sec = ts.tv_sec;	event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC; 	/* Interrupts are disabled, just acquire the lock. */	spin_lock(&client->buffer_lock); 	for (v = vals; v != vals + count; v++) {		if (__evdev_is_filtered(client, v->type, v->code))			continue; 		if (v->type == EV_SYN && v->code == SYN_REPORT) {			/* drop empty SYN_REPORT */			if (client->packet_head == client->head)				continue; 			wakeup = true;		} 		event.type = v->type;		event.code = v->code;		event.value = v->value;		__pass_event(client, &event);	} 	spin_unlock(&client->buffer_lock); 	if (wakeup)		wake_up_interruptible(&evdev->wait);} /* * Pass incoming events to all connected clients. */static void evdev_events(struct input_handle *handle,			 const struct input_value *vals, unsigned int count){	struct evdev *evdev = handle->private;	struct evdev_client *client;	ktime_t ev_time[EV_CLK_MAX]; 	ev_time[EV_CLK_MONO] = ktime_get();	ev_time[EV_CLK_REAL] = ktime_mono_to_real(ev_time[EV_CLK_MONO]);	ev_time[EV_CLK_BOOT] = ktime_mono_to_any(ev_time[EV_CLK_MONO],						 TK_OFFS_BOOT); 	rcu_read_lock(); 	client = rcu_dereference(evdev->grab); 	if (client)		evdev_pass_values(client, vals, count, ev_time);	else		list_for_each_entry_rcu(client, &evdev->client_list, node)			evdev_pass_values(client, vals, count, ev_time); 	rcu_read_unlock();} /* * Pass incoming event to all connected clients. */static void evdev_event(struct input_handle *handle,			unsigned int type, unsigned int code, int value){	struct input_value vals[] = { { type, code, value } }; 	evdev_events(handle, vals, 1);} static int evdev_fasync(int fd, struct file *file, int on){	struct evdev_client *client = file->private_data; 	return fasync_helper(fd, file, on, &client->fasync);} static int evdev_flush(struct file *file, fl_owner_t id){	struct evdev_client *client = file->private_data;	struct evdev *evdev = client->evdev; 	mutex_lock(&evdev->mutex); 	if (evdev->exist && !client->revoked)		input_flush_device(&evdev->handle, file); 	mutex_unlock(&evdev->mutex);	return 0;} static void evdev_free(struct device *dev){	struct evdev *evdev = container_of(dev, struct evdev, dev); 	input_put_device(evdev->handle.dev);	kfree(evdev);} /* * Grabs an event device (along with underlying input device). * This function is called with evdev->mutex taken. */static int evdev_grab(struct evdev *evdev, struct evdev_client *client){	int error; 	if (evdev->grab)		return -EBUSY; 	error = input_grab_device(&evdev->handle);	if (error)		return error; 	rcu_assign_pointer(evdev->grab, client); 	return 0;} static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client){	struct evdev_client *grab = rcu_dereference_protected(evdev->grab,					lockdep_is_held(&evdev->mutex)); 	if (grab != client)		return  -EINVAL; 	rcu_assign_pointer(evdev->grab, NULL);	synchronize_rcu();	input_release_device(&evdev->handle); 	return 0;} static void evdev_attach_client(struct evdev *evdev,				struct evdev_client *client){	spin_lock(&evdev->client_lock);	list_add_tail_rcu(&client->node, &evdev->client_list);	spin_unlock(&evdev->client_lock);} static void evdev_detach_client(struct evdev *evdev,				struct evdev_client *client){	spin_lock(&evdev->client_lock);	list_del_rcu(&client->node);	spin_unlock(&evdev->client_lock);	synchronize_rcu();} static int evdev_open_device(struct evdev *evdev){	int retval; 	retval = mutex_lock_interruptible(&evdev->mutex);	if (retval)		return retval; 	if (!evdev->exist)		retval = -ENODEV;	else if (!evdev->open++) {		retval = input_open_device(&evdev->handle);		if (retval)			evdev->open--;	} 	mutex_unlock(&evdev->mutex);	return retval;} static void evdev_close_device(struct evdev *evdev){	mutex_lock(&evdev->mutex); 	if (evdev->exist && !--evdev->open)		input_close_device(&evdev->handle); 	mutex_unlock(&evdev->mutex);} /* * Wake up users waiting for IO so they can disconnect from * dead device. */static void evdev_hangup(struct evdev *evdev){	struct evdev_client *client; 	spin_lock(&evdev->client_lock);	list_for_each_entry(client, &evdev->client_list, node)		kill_fasync(&client->fasync, SIGIO, POLL_HUP);	spin_unlock(&evdev->client_lock); 	wake_up_interruptible(&evdev->wait);} static int evdev_release(struct inode *inode, struct file *file){	struct evdev_client *client = file->private_data;	struct evdev *evdev = client->evdev;	unsigned int i; 	mutex_lock(&evdev->mutex);	evdev_ungrab(evdev, client);	mutex_unlock(&evdev->mutex); 	evdev_detach_client(evdev, client); 	for (i = 0; i < EV_CNT; ++i)		bitmap_free(client->evmasks[i]); 	kvfree(client); 	evdev_close_device(evdev); 	return 0;} static unsigned int evdev_compute_buffer_size(struct input_dev *dev){	unsigned int n_events =		max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS,		    EVDEV_MIN_BUFFER_SIZE); 	return roundup_pow_of_two(n_events);}

Lines 1–500 of 1482.