linux/drivers/input/evdev.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Event char devices, giving access to raw input device events.
 *
 * Copyright (c) 1999-2002 Vojtech Pavlik
 */

#define pr_fmt(fmt)

#define EVDEV_MINOR_BASE
#define EVDEV_MINORS
#define EVDEV_MIN_BUFFER_SIZE
#define EVDEV_BUF_PACKETS

#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"

struct evdev {};

struct evdev_client {};

static size_t evdev_get_mask_cnt(unsigned int type)
{}

/* requires the buffer lock to be held */
static bool __evdev_is_filtered(struct evdev_client *client,
				unsigned int type,
				unsigned int code)
{}

/* flush queued events of type @type, caller must hold client->buffer_lock */
static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
{}

static void __evdev_queue_syn_dropped(struct evdev_client *client)
{}

static void evdev_queue_syn_dropped(struct evdev_client *client)
{}

static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
{}

static void __pass_event(struct evdev_client *client,
			 const struct input_event *event)
{}

static void evdev_pass_values(struct evdev_client *client,
			const struct input_value *vals, unsigned int count,
			ktime_t *ev_time)
{}

/*
 * Pass incoming events to all connected clients.
 */
static unsigned int evdev_events(struct input_handle *handle,
				 struct input_value *vals, unsigned int count)
{}

static int evdev_fasync(int fd, struct file *file, int on)
{}

static void evdev_free(struct device *dev)
{}

/*
 * 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)
{}

static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
{}

static void evdev_attach_client(struct evdev *evdev,
				struct evdev_client *client)
{}

static void evdev_detach_client(struct evdev *evdev,
				struct evdev_client *client)
{}

static int evdev_open_device(struct evdev *evdev)
{}

static void evdev_close_device(struct evdev *evdev)
{}

/*
 * Wake up users waiting for IO so they can disconnect from
 * dead device.
 */
static void evdev_hangup(struct evdev *evdev)
{}

static int evdev_release(struct inode *inode, struct file *file)
{}

static unsigned int evdev_compute_buffer_size(struct input_dev *dev)
{}

static int evdev_open(struct inode *inode, struct file *file)
{}

static ssize_t evdev_write(struct file *file, const char __user *buffer,
			   size_t count, loff_t *ppos)
{}

static int evdev_fetch_next_event(struct evdev_client *client,
				  struct input_event *event)
{}

static ssize_t evdev_read(struct file *file, char __user *buffer,
			  size_t count, loff_t *ppos)
{}

/* No kernel lock - fine */
static __poll_t evdev_poll(struct file *file, poll_table *wait)
{}

#ifdef CONFIG_COMPAT

#define BITS_PER_LONG_COMPAT
#define BITS_TO_LONGS_COMPAT(x)

#ifdef __BIG_ENDIAN
static int bits_to_user(unsigned long *bits, unsigned int maxbit,
			unsigned int maxlen, void __user *p, int compat)
{
	int len, i;

	if (compat) {
		len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t);
		if (len > maxlen)
			len = maxlen;

		for (i = 0; i < len / sizeof(compat_long_t); i++)
			if (copy_to_user((compat_long_t __user *) p + i,
					 (compat_long_t *) bits +
						i + 1 - ((i % 2) << 1),
					 sizeof(compat_long_t)))
				return -EFAULT;
	} else {
		len = BITS_TO_LONGS(maxbit) * sizeof(long);
		if (len > maxlen)
			len = maxlen;

		if (copy_to_user(p, bits, len))
			return -EFAULT;
	}

	return len;
}

static int bits_from_user(unsigned long *bits, unsigned int maxbit,
			  unsigned int maxlen, const void __user *p, int compat)
{
	int len, i;

	if (compat) {
		if (maxlen % sizeof(compat_long_t))
			return -EINVAL;

		len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t);
		if (len > maxlen)
			len = maxlen;

		for (i = 0; i < len / sizeof(compat_long_t); i++)
			if (copy_from_user((compat_long_t *) bits +
						i + 1 - ((i % 2) << 1),
					   (compat_long_t __user *) p + i,
					   sizeof(compat_long_t)))
				return -EFAULT;
		if (i % 2)
			*((compat_long_t *) bits + i - 1) = 0;

	} else {
		if (maxlen % sizeof(long))
			return -EINVAL;

		len = BITS_TO_LONGS(maxbit) * sizeof(long);
		if (len > maxlen)
			len = maxlen;

		if (copy_from_user(bits, p, len))
			return -EFAULT;
	}

	return len;
}

#else

static int bits_to_user(unsigned long *bits, unsigned int maxbit,
			unsigned int maxlen, void __user *p, int compat)
{}

static int bits_from_user(unsigned long *bits, unsigned int maxbit,
			  unsigned int maxlen, const void __user *p, int compat)
{}

#endif /* __BIG_ENDIAN */

#else

static int bits_to_user(unsigned long *bits, unsigned int maxbit,
			unsigned int maxlen, void __user *p, int compat)
{
	int len = BITS_TO_LONGS(maxbit) * sizeof(long);

	if (len > maxlen)
		len = maxlen;

	return copy_to_user(p, bits, len) ? -EFAULT : len;
}

static int bits_from_user(unsigned long *bits, unsigned int maxbit,
			  unsigned int maxlen, const void __user *p, int compat)
{
	int len;

	if (maxlen % sizeof(long))
		return -EINVAL;

	len = BITS_TO_LONGS(maxbit) * sizeof(long);
	if (len > maxlen)
		len = maxlen;

	return copy_from_user(bits, p, len) ? -EFAULT : len;
}

#endif /* CONFIG_COMPAT */

static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
{}

static int handle_eviocgbit(struct input_dev *dev,
			    unsigned int type, unsigned int size,
			    void __user *p, int compat_mode)
{}

static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)
{}

static int evdev_handle_get_keycode_v2(struct input_dev *dev, void __user *p)
{}

static int evdev_handle_set_keycode(struct input_dev *dev, void __user *p)
{}

static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p)
{}

/*
 * If we transfer state to the user, we should flush all pending events
 * of the same type from the client's queue. Otherwise, they might end up
 * with duplicate events, which can screw up client's state tracking.
 * If bits_to_user fails after flushing the queue, we queue a SYN_DROPPED
 * event so user-space will notice missing events.
 *
 * LOCKING:
 * We need to take event_lock before buffer_lock to avoid dead-locks. But we
 * need the even_lock only to guarantee consistent state. We can safely release
 * it while flushing the queue. This allows input-core to handle filters while
 * we flush the queue.
 */
static int evdev_handle_get_val(struct evdev_client *client,
				struct input_dev *dev, unsigned int type,
				unsigned long *bits, unsigned int maxbit,
				unsigned int maxlen, void __user *p,
				int compat)
{}

static int evdev_handle_mt_request(struct input_dev *dev,
				   unsigned int size,
				   int __user *ip)
{}

static int evdev_revoke(struct evdev *evdev, struct evdev_client *client,
			struct file *file)
{}

/* must be called with evdev-mutex held */
static int evdev_set_mask(struct evdev_client *client,
			  unsigned int type,
			  const void __user *codes,
			  u32 codes_size,
			  int compat)
{}

/* must be called with evdev-mutex held */
static int evdev_get_mask(struct evdev_client *client,
			  unsigned int type,
			  void __user *codes,
			  u32 codes_size,
			  int compat)
{}

static long evdev_do_ioctl(struct file *file, unsigned int cmd,
			   void __user *p, int compat_mode)
{}

static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
				void __user *p, int compat_mode)
{}

static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{}

#ifdef CONFIG_COMPAT
static long evdev_ioctl_compat(struct file *file,
				unsigned int cmd, unsigned long arg)
{}
#endif

static const struct file_operations evdev_fops =;

/*
 * 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 evdev_mark_dead(struct evdev *evdev)
{}

static void evdev_cleanup(struct evdev *evdev)
{}

/*
 * Create new evdev device. Note that input core serializes calls
 * to connect and disconnect.
 */
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
			 const struct input_device_id *id)
{}

static void evdev_disconnect(struct input_handle *handle)
{}

static const struct input_device_id evdev_ids[] =;

MODULE_DEVICE_TABLE(input, evdev_ids);

static struct input_handler evdev_handler =;

static int __init evdev_init(void)
{}

static void __exit evdev_exit(void)
{}

module_init();
module_exit(evdev_exit);

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();