162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  User level driver support for input subsystem
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Heavily based on evdev.c by Vojtech Pavlik
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Changes/Revisions:
1062306a36Sopenharmony_ci *	0.4	01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
1162306a36Sopenharmony_ci *		- add UI_GET_SYSNAME ioctl
1262306a36Sopenharmony_ci *	0.3	09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>)
1362306a36Sopenharmony_ci *		- updated ff support for the changes in kernel interface
1462306a36Sopenharmony_ci *		- added MODULE_VERSION
1562306a36Sopenharmony_ci *	0.2	16/10/2004 (Micah Dowty <micah@navi.cx>)
1662306a36Sopenharmony_ci *		- added force feedback support
1762306a36Sopenharmony_ci *              - added UI_SET_PHYS
1862306a36Sopenharmony_ci *	0.1	20/06/2002
1962306a36Sopenharmony_ci *		- first public version
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci#include <uapi/linux/uinput.h>
2262306a36Sopenharmony_ci#include <linux/poll.h>
2362306a36Sopenharmony_ci#include <linux/sched.h>
2462306a36Sopenharmony_ci#include <linux/slab.h>
2562306a36Sopenharmony_ci#include <linux/module.h>
2662306a36Sopenharmony_ci#include <linux/init.h>
2762306a36Sopenharmony_ci#include <linux/fs.h>
2862306a36Sopenharmony_ci#include <linux/miscdevice.h>
2962306a36Sopenharmony_ci#include <linux/overflow.h>
3062306a36Sopenharmony_ci#include <linux/input/mt.h>
3162306a36Sopenharmony_ci#include "../input-compat.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define UINPUT_NAME		"uinput"
3462306a36Sopenharmony_ci#define UINPUT_BUFFER_SIZE	16
3562306a36Sopenharmony_ci#define UINPUT_NUM_REQUESTS	16
3662306a36Sopenharmony_ci#define UINPUT_TIMESTAMP_ALLOWED_OFFSET_SECS 10
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cienum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED };
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistruct uinput_request {
4162306a36Sopenharmony_ci	unsigned int		id;
4262306a36Sopenharmony_ci	unsigned int		code;	/* UI_FF_UPLOAD, UI_FF_ERASE */
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	int			retval;
4562306a36Sopenharmony_ci	struct completion	done;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	union {
4862306a36Sopenharmony_ci		unsigned int	effect_id;
4962306a36Sopenharmony_ci		struct {
5062306a36Sopenharmony_ci			struct ff_effect *effect;
5162306a36Sopenharmony_ci			struct ff_effect *old;
5262306a36Sopenharmony_ci		} upload;
5362306a36Sopenharmony_ci	} u;
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistruct uinput_device {
5762306a36Sopenharmony_ci	struct input_dev	*dev;
5862306a36Sopenharmony_ci	struct mutex		mutex;
5962306a36Sopenharmony_ci	enum uinput_state	state;
6062306a36Sopenharmony_ci	wait_queue_head_t	waitq;
6162306a36Sopenharmony_ci	unsigned char		ready;
6262306a36Sopenharmony_ci	unsigned char		head;
6362306a36Sopenharmony_ci	unsigned char		tail;
6462306a36Sopenharmony_ci	struct input_event	buff[UINPUT_BUFFER_SIZE];
6562306a36Sopenharmony_ci	unsigned int		ff_effects_max;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	struct uinput_request	*requests[UINPUT_NUM_REQUESTS];
6862306a36Sopenharmony_ci	wait_queue_head_t	requests_waitq;
6962306a36Sopenharmony_ci	spinlock_t		requests_lock;
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic int uinput_dev_event(struct input_dev *dev,
7362306a36Sopenharmony_ci			    unsigned int type, unsigned int code, int value)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct uinput_device	*udev = input_get_drvdata(dev);
7662306a36Sopenharmony_ci	struct timespec64	ts;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	ktime_get_ts64(&ts);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	udev->buff[udev->head] = (struct input_event) {
8162306a36Sopenharmony_ci		.input_event_sec = ts.tv_sec,
8262306a36Sopenharmony_ci		.input_event_usec = ts.tv_nsec / NSEC_PER_USEC,
8362306a36Sopenharmony_ci		.type = type,
8462306a36Sopenharmony_ci		.code = code,
8562306a36Sopenharmony_ci		.value = value,
8662306a36Sopenharmony_ci	};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	wake_up_interruptible(&udev->waitq);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	return 0;
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* Atomically allocate an ID for the given request. Returns 0 on success. */
9662306a36Sopenharmony_cistatic bool uinput_request_alloc_id(struct uinput_device *udev,
9762306a36Sopenharmony_ci				    struct uinput_request *request)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	unsigned int id;
10062306a36Sopenharmony_ci	bool reserved = false;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	spin_lock(&udev->requests_lock);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	for (id = 0; id < UINPUT_NUM_REQUESTS; id++) {
10562306a36Sopenharmony_ci		if (!udev->requests[id]) {
10662306a36Sopenharmony_ci			request->id = id;
10762306a36Sopenharmony_ci			udev->requests[id] = request;
10862306a36Sopenharmony_ci			reserved = true;
10962306a36Sopenharmony_ci			break;
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	spin_unlock(&udev->requests_lock);
11462306a36Sopenharmony_ci	return reserved;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic struct uinput_request *uinput_request_find(struct uinput_device *udev,
11862306a36Sopenharmony_ci						  unsigned int id)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	/* Find an input request, by ID. Returns NULL if the ID isn't valid. */
12162306a36Sopenharmony_ci	if (id >= UINPUT_NUM_REQUESTS)
12262306a36Sopenharmony_ci		return NULL;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return udev->requests[id];
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int uinput_request_reserve_slot(struct uinput_device *udev,
12862306a36Sopenharmony_ci				       struct uinput_request *request)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	/* Allocate slot. If none are available right away, wait. */
13162306a36Sopenharmony_ci	return wait_event_interruptible(udev->requests_waitq,
13262306a36Sopenharmony_ci					uinput_request_alloc_id(udev, request));
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic void uinput_request_release_slot(struct uinput_device *udev,
13662306a36Sopenharmony_ci					unsigned int id)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	/* Mark slot as available */
13962306a36Sopenharmony_ci	spin_lock(&udev->requests_lock);
14062306a36Sopenharmony_ci	udev->requests[id] = NULL;
14162306a36Sopenharmony_ci	spin_unlock(&udev->requests_lock);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	wake_up(&udev->requests_waitq);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int uinput_request_send(struct uinput_device *udev,
14762306a36Sopenharmony_ci			       struct uinput_request *request)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	int retval;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	retval = mutex_lock_interruptible(&udev->mutex);
15262306a36Sopenharmony_ci	if (retval)
15362306a36Sopenharmony_ci		return retval;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (udev->state != UIST_CREATED) {
15662306a36Sopenharmony_ci		retval = -ENODEV;
15762306a36Sopenharmony_ci		goto out;
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	init_completion(&request->done);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/*
16362306a36Sopenharmony_ci	 * Tell our userspace application about this new request
16462306a36Sopenharmony_ci	 * by queueing an input event.
16562306a36Sopenharmony_ci	 */
16662306a36Sopenharmony_ci	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci out:
16962306a36Sopenharmony_ci	mutex_unlock(&udev->mutex);
17062306a36Sopenharmony_ci	return retval;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic int uinput_request_submit(struct uinput_device *udev,
17462306a36Sopenharmony_ci				 struct uinput_request *request)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	int retval;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	retval = uinput_request_reserve_slot(udev, request);
17962306a36Sopenharmony_ci	if (retval)
18062306a36Sopenharmony_ci		return retval;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	retval = uinput_request_send(udev, request);
18362306a36Sopenharmony_ci	if (retval)
18462306a36Sopenharmony_ci		goto out;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&request->done, 30 * HZ)) {
18762306a36Sopenharmony_ci		retval = -ETIMEDOUT;
18862306a36Sopenharmony_ci		goto out;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	retval = request->retval;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci out:
19462306a36Sopenharmony_ci	uinput_request_release_slot(udev, request->id);
19562306a36Sopenharmony_ci	return retval;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/*
19962306a36Sopenharmony_ci * Fail all outstanding requests so handlers don't wait for the userspace
20062306a36Sopenharmony_ci * to finish processing them.
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_cistatic void uinput_flush_requests(struct uinput_device *udev)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct uinput_request *request;
20562306a36Sopenharmony_ci	int i;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	spin_lock(&udev->requests_lock);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	for (i = 0; i < UINPUT_NUM_REQUESTS; i++) {
21062306a36Sopenharmony_ci		request = udev->requests[i];
21162306a36Sopenharmony_ci		if (request) {
21262306a36Sopenharmony_ci			request->retval = -ENODEV;
21362306a36Sopenharmony_ci			complete(&request->done);
21462306a36Sopenharmony_ci		}
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	spin_unlock(&udev->requests_lock);
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic void uinput_dev_set_gain(struct input_dev *dev, u16 gain)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	uinput_dev_event(dev, EV_FF, FF_GAIN, gain);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude);
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic int uinput_dev_playback(struct input_dev *dev, int effect_id, int value)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	return uinput_dev_event(dev, EV_FF, effect_id, value);
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic int uinput_dev_upload_effect(struct input_dev *dev,
23662306a36Sopenharmony_ci				    struct ff_effect *effect,
23762306a36Sopenharmony_ci				    struct ff_effect *old)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	struct uinput_device *udev = input_get_drvdata(dev);
24062306a36Sopenharmony_ci	struct uinput_request request;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	/*
24362306a36Sopenharmony_ci	 * uinput driver does not currently support periodic effects with
24462306a36Sopenharmony_ci	 * custom waveform since it does not have a way to pass buffer of
24562306a36Sopenharmony_ci	 * samples (custom_data) to userspace. If ever there is a device
24662306a36Sopenharmony_ci	 * supporting custom waveforms we would need to define an additional
24762306a36Sopenharmony_ci	 * ioctl (UI_UPLOAD_SAMPLES) but for now we just bail out.
24862306a36Sopenharmony_ci	 */
24962306a36Sopenharmony_ci	if (effect->type == FF_PERIODIC &&
25062306a36Sopenharmony_ci			effect->u.periodic.waveform == FF_CUSTOM)
25162306a36Sopenharmony_ci		return -EINVAL;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	request.code = UI_FF_UPLOAD;
25462306a36Sopenharmony_ci	request.u.upload.effect = effect;
25562306a36Sopenharmony_ci	request.u.upload.old = old;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return uinput_request_submit(udev, &request);
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct uinput_device *udev = input_get_drvdata(dev);
26362306a36Sopenharmony_ci	struct uinput_request request;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (!test_bit(EV_FF, dev->evbit))
26662306a36Sopenharmony_ci		return -ENOSYS;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	request.code = UI_FF_ERASE;
26962306a36Sopenharmony_ci	request.u.effect_id = effect_id;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	return uinput_request_submit(udev, &request);
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic int uinput_dev_flush(struct input_dev *dev, struct file *file)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	/*
27762306a36Sopenharmony_ci	 * If we are called with file == NULL that means we are tearing
27862306a36Sopenharmony_ci	 * down the device, and therefore we can not handle FF erase
27962306a36Sopenharmony_ci	 * requests: either we are handling UI_DEV_DESTROY (and holding
28062306a36Sopenharmony_ci	 * the udev->mutex), or the file descriptor is closed and there is
28162306a36Sopenharmony_ci	 * nobody on the other side anymore.
28262306a36Sopenharmony_ci	 */
28362306a36Sopenharmony_ci	return file ? input_ff_flush(dev, file) : 0;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic void uinput_destroy_device(struct uinput_device *udev)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	const char *name, *phys;
28962306a36Sopenharmony_ci	struct input_dev *dev = udev->dev;
29062306a36Sopenharmony_ci	enum uinput_state old_state = udev->state;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	udev->state = UIST_NEW_DEVICE;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (dev) {
29562306a36Sopenharmony_ci		name = dev->name;
29662306a36Sopenharmony_ci		phys = dev->phys;
29762306a36Sopenharmony_ci		if (old_state == UIST_CREATED) {
29862306a36Sopenharmony_ci			uinput_flush_requests(udev);
29962306a36Sopenharmony_ci			input_unregister_device(dev);
30062306a36Sopenharmony_ci		} else {
30162306a36Sopenharmony_ci			input_free_device(dev);
30262306a36Sopenharmony_ci		}
30362306a36Sopenharmony_ci		kfree(name);
30462306a36Sopenharmony_ci		kfree(phys);
30562306a36Sopenharmony_ci		udev->dev = NULL;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic int uinput_create_device(struct uinput_device *udev)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct input_dev *dev = udev->dev;
31262306a36Sopenharmony_ci	int error, nslot;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (udev->state != UIST_SETUP_COMPLETE) {
31562306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
31662306a36Sopenharmony_ci		return -EINVAL;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (test_bit(EV_ABS, dev->evbit)) {
32062306a36Sopenharmony_ci		input_alloc_absinfo(dev);
32162306a36Sopenharmony_ci		if (!dev->absinfo) {
32262306a36Sopenharmony_ci			error = -EINVAL;
32362306a36Sopenharmony_ci			goto fail1;
32462306a36Sopenharmony_ci		}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		if (test_bit(ABS_MT_SLOT, dev->absbit)) {
32762306a36Sopenharmony_ci			nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
32862306a36Sopenharmony_ci			error = input_mt_init_slots(dev, nslot, 0);
32962306a36Sopenharmony_ci			if (error)
33062306a36Sopenharmony_ci				goto fail1;
33162306a36Sopenharmony_ci		} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
33262306a36Sopenharmony_ci			input_set_events_per_packet(dev, 60);
33362306a36Sopenharmony_ci		}
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (test_bit(EV_FF, dev->evbit) && !udev->ff_effects_max) {
33762306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: ff_effects_max should be non-zero when FF_BIT is set\n",
33862306a36Sopenharmony_ci			UINPUT_NAME);
33962306a36Sopenharmony_ci		error = -EINVAL;
34062306a36Sopenharmony_ci		goto fail1;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (udev->ff_effects_max) {
34462306a36Sopenharmony_ci		error = input_ff_create(dev, udev->ff_effects_max);
34562306a36Sopenharmony_ci		if (error)
34662306a36Sopenharmony_ci			goto fail1;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		dev->ff->upload = uinput_dev_upload_effect;
34962306a36Sopenharmony_ci		dev->ff->erase = uinput_dev_erase_effect;
35062306a36Sopenharmony_ci		dev->ff->playback = uinput_dev_playback;
35162306a36Sopenharmony_ci		dev->ff->set_gain = uinput_dev_set_gain;
35262306a36Sopenharmony_ci		dev->ff->set_autocenter = uinput_dev_set_autocenter;
35362306a36Sopenharmony_ci		/*
35462306a36Sopenharmony_ci		 * The standard input_ff_flush() implementation does
35562306a36Sopenharmony_ci		 * not quite work for uinput as we can't reasonably
35662306a36Sopenharmony_ci		 * handle FF requests during device teardown.
35762306a36Sopenharmony_ci		 */
35862306a36Sopenharmony_ci		dev->flush = uinput_dev_flush;
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	dev->event = uinput_dev_event;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	input_set_drvdata(udev->dev, udev);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	error = input_register_device(udev->dev);
36662306a36Sopenharmony_ci	if (error)
36762306a36Sopenharmony_ci		goto fail2;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	udev->state = UIST_CREATED;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	return 0;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci fail2:	input_ff_destroy(dev);
37462306a36Sopenharmony_ci fail1: uinput_destroy_device(udev);
37562306a36Sopenharmony_ci	return error;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic int uinput_open(struct inode *inode, struct file *file)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	struct uinput_device *newdev;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	newdev = kzalloc(sizeof(struct uinput_device), GFP_KERNEL);
38362306a36Sopenharmony_ci	if (!newdev)
38462306a36Sopenharmony_ci		return -ENOMEM;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	mutex_init(&newdev->mutex);
38762306a36Sopenharmony_ci	spin_lock_init(&newdev->requests_lock);
38862306a36Sopenharmony_ci	init_waitqueue_head(&newdev->requests_waitq);
38962306a36Sopenharmony_ci	init_waitqueue_head(&newdev->waitq);
39062306a36Sopenharmony_ci	newdev->state = UIST_NEW_DEVICE;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	file->private_data = newdev;
39362306a36Sopenharmony_ci	stream_open(inode, file);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	return 0;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,
39962306a36Sopenharmony_ci				   const struct input_absinfo *abs)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	int min, max, range;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	min = abs->minimum;
40462306a36Sopenharmony_ci	max = abs->maximum;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	if ((min != 0 || max != 0) && max < min) {
40762306a36Sopenharmony_ci		printk(KERN_DEBUG
40862306a36Sopenharmony_ci		       "%s: invalid abs[%02x] min:%d max:%d\n",
40962306a36Sopenharmony_ci		       UINPUT_NAME, code, min, max);
41062306a36Sopenharmony_ci		return -EINVAL;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (!check_sub_overflow(max, min, &range) && abs->flat > range) {
41462306a36Sopenharmony_ci		printk(KERN_DEBUG
41562306a36Sopenharmony_ci		       "%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",
41662306a36Sopenharmony_ci		       UINPUT_NAME, code, abs->flat, min, max);
41762306a36Sopenharmony_ci		return -EINVAL;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	return 0;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic int uinput_validate_absbits(struct input_dev *dev)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	unsigned int cnt;
42662306a36Sopenharmony_ci	int error;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	if (!test_bit(EV_ABS, dev->evbit))
42962306a36Sopenharmony_ci		return 0;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	/*
43262306a36Sopenharmony_ci	 * Check if absmin/absmax/absfuzz/absflat are sane.
43362306a36Sopenharmony_ci	 */
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	for_each_set_bit(cnt, dev->absbit, ABS_CNT) {
43662306a36Sopenharmony_ci		if (!dev->absinfo)
43762306a36Sopenharmony_ci			return -EINVAL;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci		error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]);
44062306a36Sopenharmony_ci		if (error)
44162306a36Sopenharmony_ci			return error;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	return 0;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic int uinput_dev_setup(struct uinput_device *udev,
44862306a36Sopenharmony_ci			    struct uinput_setup __user *arg)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	struct uinput_setup setup;
45162306a36Sopenharmony_ci	struct input_dev *dev;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (udev->state == UIST_CREATED)
45462306a36Sopenharmony_ci		return -EINVAL;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	if (copy_from_user(&setup, arg, sizeof(setup)))
45762306a36Sopenharmony_ci		return -EFAULT;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	if (!setup.name[0])
46062306a36Sopenharmony_ci		return -EINVAL;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	dev = udev->dev;
46362306a36Sopenharmony_ci	dev->id = setup.id;
46462306a36Sopenharmony_ci	udev->ff_effects_max = setup.ff_effects_max;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	kfree(dev->name);
46762306a36Sopenharmony_ci	dev->name = kstrndup(setup.name, UINPUT_MAX_NAME_SIZE, GFP_KERNEL);
46862306a36Sopenharmony_ci	if (!dev->name)
46962306a36Sopenharmony_ci		return -ENOMEM;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	udev->state = UIST_SETUP_COMPLETE;
47262306a36Sopenharmony_ci	return 0;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic int uinput_abs_setup(struct uinput_device *udev,
47662306a36Sopenharmony_ci			    struct uinput_setup __user *arg, size_t size)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	struct uinput_abs_setup setup = {};
47962306a36Sopenharmony_ci	struct input_dev *dev;
48062306a36Sopenharmony_ci	int error;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	if (size > sizeof(setup))
48362306a36Sopenharmony_ci		return -E2BIG;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (udev->state == UIST_CREATED)
48662306a36Sopenharmony_ci		return -EINVAL;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (copy_from_user(&setup, arg, size))
48962306a36Sopenharmony_ci		return -EFAULT;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (setup.code > ABS_MAX)
49262306a36Sopenharmony_ci		return -ERANGE;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	dev = udev->dev;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	error = uinput_validate_absinfo(dev, setup.code, &setup.absinfo);
49762306a36Sopenharmony_ci	if (error)
49862306a36Sopenharmony_ci		return error;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	input_alloc_absinfo(dev);
50162306a36Sopenharmony_ci	if (!dev->absinfo)
50262306a36Sopenharmony_ci		return -ENOMEM;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	set_bit(setup.code, dev->absbit);
50562306a36Sopenharmony_ci	dev->absinfo[setup.code] = setup.absinfo;
50662306a36Sopenharmony_ci	return 0;
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci/* legacy setup via write() */
51062306a36Sopenharmony_cistatic int uinput_setup_device_legacy(struct uinput_device *udev,
51162306a36Sopenharmony_ci				      const char __user *buffer, size_t count)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	struct uinput_user_dev	*user_dev;
51462306a36Sopenharmony_ci	struct input_dev	*dev;
51562306a36Sopenharmony_ci	int			i;
51662306a36Sopenharmony_ci	int			retval;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	if (count != sizeof(struct uinput_user_dev))
51962306a36Sopenharmony_ci		return -EINVAL;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (!udev->dev) {
52262306a36Sopenharmony_ci		udev->dev = input_allocate_device();
52362306a36Sopenharmony_ci		if (!udev->dev)
52462306a36Sopenharmony_ci			return -ENOMEM;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	dev = udev->dev;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev));
53062306a36Sopenharmony_ci	if (IS_ERR(user_dev))
53162306a36Sopenharmony_ci		return PTR_ERR(user_dev);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	udev->ff_effects_max = user_dev->ff_effects_max;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	/* Ensure name is filled in */
53662306a36Sopenharmony_ci	if (!user_dev->name[0]) {
53762306a36Sopenharmony_ci		retval = -EINVAL;
53862306a36Sopenharmony_ci		goto exit;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	kfree(dev->name);
54262306a36Sopenharmony_ci	dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE,
54362306a36Sopenharmony_ci			     GFP_KERNEL);
54462306a36Sopenharmony_ci	if (!dev->name) {
54562306a36Sopenharmony_ci		retval = -ENOMEM;
54662306a36Sopenharmony_ci		goto exit;
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	dev->id.bustype	= user_dev->id.bustype;
55062306a36Sopenharmony_ci	dev->id.vendor	= user_dev->id.vendor;
55162306a36Sopenharmony_ci	dev->id.product	= user_dev->id.product;
55262306a36Sopenharmony_ci	dev->id.version	= user_dev->id.version;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	for (i = 0; i < ABS_CNT; i++) {
55562306a36Sopenharmony_ci		input_abs_set_max(dev, i, user_dev->absmax[i]);
55662306a36Sopenharmony_ci		input_abs_set_min(dev, i, user_dev->absmin[i]);
55762306a36Sopenharmony_ci		input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]);
55862306a36Sopenharmony_ci		input_abs_set_flat(dev, i, user_dev->absflat[i]);
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	retval = uinput_validate_absbits(dev);
56262306a36Sopenharmony_ci	if (retval < 0)
56362306a36Sopenharmony_ci		goto exit;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	udev->state = UIST_SETUP_COMPLETE;
56662306a36Sopenharmony_ci	retval = count;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci exit:
56962306a36Sopenharmony_ci	kfree(user_dev);
57062306a36Sopenharmony_ci	return retval;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci/*
57462306a36Sopenharmony_ci * Returns true if the given timestamp is valid (i.e., if all the following
57562306a36Sopenharmony_ci * conditions are satisfied), false otherwise.
57662306a36Sopenharmony_ci * 1) given timestamp is positive
57762306a36Sopenharmony_ci * 2) it's within the allowed offset before the current time
57862306a36Sopenharmony_ci * 3) it's not in the future
57962306a36Sopenharmony_ci */
58062306a36Sopenharmony_cistatic bool is_valid_timestamp(const ktime_t timestamp)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	ktime_t zero_time;
58362306a36Sopenharmony_ci	ktime_t current_time;
58462306a36Sopenharmony_ci	ktime_t min_time;
58562306a36Sopenharmony_ci	ktime_t offset;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	zero_time = ktime_set(0, 0);
58862306a36Sopenharmony_ci	if (ktime_compare(zero_time, timestamp) >= 0)
58962306a36Sopenharmony_ci		return false;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	current_time = ktime_get();
59262306a36Sopenharmony_ci	offset = ktime_set(UINPUT_TIMESTAMP_ALLOWED_OFFSET_SECS, 0);
59362306a36Sopenharmony_ci	min_time = ktime_sub(current_time, offset);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	if (ktime_after(min_time, timestamp) || ktime_after(timestamp, current_time))
59662306a36Sopenharmony_ci		return false;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	return true;
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic ssize_t uinput_inject_events(struct uinput_device *udev,
60262306a36Sopenharmony_ci				    const char __user *buffer, size_t count)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	struct input_event ev;
60562306a36Sopenharmony_ci	size_t bytes = 0;
60662306a36Sopenharmony_ci	ktime_t timestamp;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	if (count != 0 && count < input_event_size())
60962306a36Sopenharmony_ci		return -EINVAL;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	while (bytes + input_event_size() <= count) {
61262306a36Sopenharmony_ci		/*
61362306a36Sopenharmony_ci		 * Note that even if some events were fetched successfully
61462306a36Sopenharmony_ci		 * we are still going to return EFAULT instead of partial
61562306a36Sopenharmony_ci		 * count to let userspace know that it got it's buffers
61662306a36Sopenharmony_ci		 * all wrong.
61762306a36Sopenharmony_ci		 */
61862306a36Sopenharmony_ci		if (input_event_from_user(buffer + bytes, &ev))
61962306a36Sopenharmony_ci			return -EFAULT;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		timestamp = ktime_set(ev.input_event_sec, ev.input_event_usec * NSEC_PER_USEC);
62262306a36Sopenharmony_ci		if (is_valid_timestamp(timestamp))
62362306a36Sopenharmony_ci			input_set_timestamp(udev->dev, timestamp);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		input_event(udev->dev, ev.type, ev.code, ev.value);
62662306a36Sopenharmony_ci		bytes += input_event_size();
62762306a36Sopenharmony_ci		cond_resched();
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	return bytes;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic ssize_t uinput_write(struct file *file, const char __user *buffer,
63462306a36Sopenharmony_ci			    size_t count, loff_t *ppos)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	struct uinput_device *udev = file->private_data;
63762306a36Sopenharmony_ci	int retval;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	if (count == 0)
64062306a36Sopenharmony_ci		return 0;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	retval = mutex_lock_interruptible(&udev->mutex);
64362306a36Sopenharmony_ci	if (retval)
64462306a36Sopenharmony_ci		return retval;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	retval = udev->state == UIST_CREATED ?
64762306a36Sopenharmony_ci			uinput_inject_events(udev, buffer, count) :
64862306a36Sopenharmony_ci			uinput_setup_device_legacy(udev, buffer, count);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	mutex_unlock(&udev->mutex);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	return retval;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic bool uinput_fetch_next_event(struct uinput_device *udev,
65662306a36Sopenharmony_ci				    struct input_event *event)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	bool have_event;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	spin_lock_irq(&udev->dev->event_lock);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	have_event = udev->head != udev->tail;
66362306a36Sopenharmony_ci	if (have_event) {
66462306a36Sopenharmony_ci		*event = udev->buff[udev->tail];
66562306a36Sopenharmony_ci		udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
66662306a36Sopenharmony_ci	}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	spin_unlock_irq(&udev->dev->event_lock);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	return have_event;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic ssize_t uinput_events_to_user(struct uinput_device *udev,
67462306a36Sopenharmony_ci				     char __user *buffer, size_t count)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	struct input_event event;
67762306a36Sopenharmony_ci	size_t read = 0;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	while (read + input_event_size() <= count &&
68062306a36Sopenharmony_ci	       uinput_fetch_next_event(udev, &event)) {
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		if (input_event_to_user(buffer + read, &event))
68362306a36Sopenharmony_ci			return -EFAULT;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci		read += input_event_size();
68662306a36Sopenharmony_ci	}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	return read;
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistatic ssize_t uinput_read(struct file *file, char __user *buffer,
69262306a36Sopenharmony_ci			   size_t count, loff_t *ppos)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	struct uinput_device *udev = file->private_data;
69562306a36Sopenharmony_ci	ssize_t retval;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (count != 0 && count < input_event_size())
69862306a36Sopenharmony_ci		return -EINVAL;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	do {
70162306a36Sopenharmony_ci		retval = mutex_lock_interruptible(&udev->mutex);
70262306a36Sopenharmony_ci		if (retval)
70362306a36Sopenharmony_ci			return retval;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		if (udev->state != UIST_CREATED)
70662306a36Sopenharmony_ci			retval = -ENODEV;
70762306a36Sopenharmony_ci		else if (udev->head == udev->tail &&
70862306a36Sopenharmony_ci			 (file->f_flags & O_NONBLOCK))
70962306a36Sopenharmony_ci			retval = -EAGAIN;
71062306a36Sopenharmony_ci		else
71162306a36Sopenharmony_ci			retval = uinput_events_to_user(udev, buffer, count);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci		mutex_unlock(&udev->mutex);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci		if (retval || count == 0)
71662306a36Sopenharmony_ci			break;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci		if (!(file->f_flags & O_NONBLOCK))
71962306a36Sopenharmony_ci			retval = wait_event_interruptible(udev->waitq,
72062306a36Sopenharmony_ci						  udev->head != udev->tail ||
72162306a36Sopenharmony_ci						  udev->state != UIST_CREATED);
72262306a36Sopenharmony_ci	} while (retval == 0);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	return retval;
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cistatic __poll_t uinput_poll(struct file *file, poll_table *wait)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	struct uinput_device *udev = file->private_data;
73062306a36Sopenharmony_ci	__poll_t mask = EPOLLOUT | EPOLLWRNORM; /* uinput is always writable */
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	poll_wait(file, &udev->waitq, wait);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	if (udev->head != udev->tail)
73562306a36Sopenharmony_ci		mask |= EPOLLIN | EPOLLRDNORM;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	return mask;
73862306a36Sopenharmony_ci}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_cistatic int uinput_release(struct inode *inode, struct file *file)
74162306a36Sopenharmony_ci{
74262306a36Sopenharmony_ci	struct uinput_device *udev = file->private_data;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	uinput_destroy_device(udev);
74562306a36Sopenharmony_ci	kfree(udev);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	return 0;
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
75162306a36Sopenharmony_cistruct uinput_ff_upload_compat {
75262306a36Sopenharmony_ci	__u32			request_id;
75362306a36Sopenharmony_ci	__s32			retval;
75462306a36Sopenharmony_ci	struct ff_effect_compat	effect;
75562306a36Sopenharmony_ci	struct ff_effect_compat	old;
75662306a36Sopenharmony_ci};
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cistatic int uinput_ff_upload_to_user(char __user *buffer,
75962306a36Sopenharmony_ci				    const struct uinput_ff_upload *ff_up)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	if (in_compat_syscall()) {
76262306a36Sopenharmony_ci		struct uinput_ff_upload_compat ff_up_compat;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci		ff_up_compat.request_id = ff_up->request_id;
76562306a36Sopenharmony_ci		ff_up_compat.retval = ff_up->retval;
76662306a36Sopenharmony_ci		/*
76762306a36Sopenharmony_ci		 * It so happens that the pointer that gives us the trouble
76862306a36Sopenharmony_ci		 * is the last field in the structure. Since we don't support
76962306a36Sopenharmony_ci		 * custom waveforms in uinput anyway we can just copy the whole
77062306a36Sopenharmony_ci		 * thing (to the compat size) and ignore the pointer.
77162306a36Sopenharmony_ci		 */
77262306a36Sopenharmony_ci		memcpy(&ff_up_compat.effect, &ff_up->effect,
77362306a36Sopenharmony_ci			sizeof(struct ff_effect_compat));
77462306a36Sopenharmony_ci		memcpy(&ff_up_compat.old, &ff_up->old,
77562306a36Sopenharmony_ci			sizeof(struct ff_effect_compat));
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci		if (copy_to_user(buffer, &ff_up_compat,
77862306a36Sopenharmony_ci				 sizeof(struct uinput_ff_upload_compat)))
77962306a36Sopenharmony_ci			return -EFAULT;
78062306a36Sopenharmony_ci	} else {
78162306a36Sopenharmony_ci		if (copy_to_user(buffer, ff_up,
78262306a36Sopenharmony_ci				 sizeof(struct uinput_ff_upload)))
78362306a36Sopenharmony_ci			return -EFAULT;
78462306a36Sopenharmony_ci	}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	return 0;
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistatic int uinput_ff_upload_from_user(const char __user *buffer,
79062306a36Sopenharmony_ci				      struct uinput_ff_upload *ff_up)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	if (in_compat_syscall()) {
79362306a36Sopenharmony_ci		struct uinput_ff_upload_compat ff_up_compat;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci		if (copy_from_user(&ff_up_compat, buffer,
79662306a36Sopenharmony_ci				   sizeof(struct uinput_ff_upload_compat)))
79762306a36Sopenharmony_ci			return -EFAULT;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci		ff_up->request_id = ff_up_compat.request_id;
80062306a36Sopenharmony_ci		ff_up->retval = ff_up_compat.retval;
80162306a36Sopenharmony_ci		memcpy(&ff_up->effect, &ff_up_compat.effect,
80262306a36Sopenharmony_ci			sizeof(struct ff_effect_compat));
80362306a36Sopenharmony_ci		memcpy(&ff_up->old, &ff_up_compat.old,
80462306a36Sopenharmony_ci			sizeof(struct ff_effect_compat));
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	} else {
80762306a36Sopenharmony_ci		if (copy_from_user(ff_up, buffer,
80862306a36Sopenharmony_ci				   sizeof(struct uinput_ff_upload)))
80962306a36Sopenharmony_ci			return -EFAULT;
81062306a36Sopenharmony_ci	}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	return 0;
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci#else
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistatic int uinput_ff_upload_to_user(char __user *buffer,
81862306a36Sopenharmony_ci				    const struct uinput_ff_upload *ff_up)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload)))
82162306a36Sopenharmony_ci		return -EFAULT;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	return 0;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic int uinput_ff_upload_from_user(const char __user *buffer,
82762306a36Sopenharmony_ci				      struct uinput_ff_upload *ff_up)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	if (copy_from_user(ff_up, buffer, sizeof(struct uinput_ff_upload)))
83062306a36Sopenharmony_ci		return -EFAULT;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	return 0;
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci#endif
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci#define uinput_set_bit(_arg, _bit, _max)		\
83862306a36Sopenharmony_ci({							\
83962306a36Sopenharmony_ci	int __ret = 0;					\
84062306a36Sopenharmony_ci	if (udev->state == UIST_CREATED)		\
84162306a36Sopenharmony_ci		__ret =  -EINVAL;			\
84262306a36Sopenharmony_ci	else if ((_arg) > (_max))			\
84362306a36Sopenharmony_ci		__ret = -EINVAL;			\
84462306a36Sopenharmony_ci	else set_bit((_arg), udev->dev->_bit);		\
84562306a36Sopenharmony_ci	__ret;						\
84662306a36Sopenharmony_ci})
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic int uinput_str_to_user(void __user *dest, const char *str,
84962306a36Sopenharmony_ci			      unsigned int maxlen)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	char __user *p = dest;
85262306a36Sopenharmony_ci	int len, ret;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	if (!str)
85562306a36Sopenharmony_ci		return -ENOENT;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	if (maxlen == 0)
85862306a36Sopenharmony_ci		return -EINVAL;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	len = strlen(str) + 1;
86162306a36Sopenharmony_ci	if (len > maxlen)
86262306a36Sopenharmony_ci		len = maxlen;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	ret = copy_to_user(p, str, len);
86562306a36Sopenharmony_ci	if (ret)
86662306a36Sopenharmony_ci		return -EFAULT;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	/* force terminating '\0' */
86962306a36Sopenharmony_ci	ret = put_user(0, p + len - 1);
87062306a36Sopenharmony_ci	return ret ? -EFAULT : len;
87162306a36Sopenharmony_ci}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_cistatic long uinput_ioctl_handler(struct file *file, unsigned int cmd,
87462306a36Sopenharmony_ci				 unsigned long arg, void __user *p)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	int			retval;
87762306a36Sopenharmony_ci	struct uinput_device	*udev = file->private_data;
87862306a36Sopenharmony_ci	struct uinput_ff_upload ff_up;
87962306a36Sopenharmony_ci	struct uinput_ff_erase  ff_erase;
88062306a36Sopenharmony_ci	struct uinput_request   *req;
88162306a36Sopenharmony_ci	char			*phys;
88262306a36Sopenharmony_ci	const char		*name;
88362306a36Sopenharmony_ci	unsigned int		size;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	retval = mutex_lock_interruptible(&udev->mutex);
88662306a36Sopenharmony_ci	if (retval)
88762306a36Sopenharmony_ci		return retval;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	if (!udev->dev) {
89062306a36Sopenharmony_ci		udev->dev = input_allocate_device();
89162306a36Sopenharmony_ci		if (!udev->dev) {
89262306a36Sopenharmony_ci			retval = -ENOMEM;
89362306a36Sopenharmony_ci			goto out;
89462306a36Sopenharmony_ci		}
89562306a36Sopenharmony_ci	}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	switch (cmd) {
89862306a36Sopenharmony_ci	case UI_GET_VERSION:
89962306a36Sopenharmony_ci		if (put_user(UINPUT_VERSION, (unsigned int __user *)p))
90062306a36Sopenharmony_ci			retval = -EFAULT;
90162306a36Sopenharmony_ci		goto out;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	case UI_DEV_CREATE:
90462306a36Sopenharmony_ci		retval = uinput_create_device(udev);
90562306a36Sopenharmony_ci		goto out;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	case UI_DEV_DESTROY:
90862306a36Sopenharmony_ci		uinput_destroy_device(udev);
90962306a36Sopenharmony_ci		goto out;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	case UI_DEV_SETUP:
91262306a36Sopenharmony_ci		retval = uinput_dev_setup(udev, p);
91362306a36Sopenharmony_ci		goto out;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	/* UI_ABS_SETUP is handled in the variable size ioctls */
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	case UI_SET_EVBIT:
91862306a36Sopenharmony_ci		retval = uinput_set_bit(arg, evbit, EV_MAX);
91962306a36Sopenharmony_ci		goto out;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	case UI_SET_KEYBIT:
92262306a36Sopenharmony_ci		retval = uinput_set_bit(arg, keybit, KEY_MAX);
92362306a36Sopenharmony_ci		goto out;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	case UI_SET_RELBIT:
92662306a36Sopenharmony_ci		retval = uinput_set_bit(arg, relbit, REL_MAX);
92762306a36Sopenharmony_ci		goto out;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	case UI_SET_ABSBIT:
93062306a36Sopenharmony_ci		retval = uinput_set_bit(arg, absbit, ABS_MAX);
93162306a36Sopenharmony_ci		goto out;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	case UI_SET_MSCBIT:
93462306a36Sopenharmony_ci		retval = uinput_set_bit(arg, mscbit, MSC_MAX);
93562306a36Sopenharmony_ci		goto out;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	case UI_SET_LEDBIT:
93862306a36Sopenharmony_ci		retval = uinput_set_bit(arg, ledbit, LED_MAX);
93962306a36Sopenharmony_ci		goto out;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	case UI_SET_SNDBIT:
94262306a36Sopenharmony_ci		retval = uinput_set_bit(arg, sndbit, SND_MAX);
94362306a36Sopenharmony_ci		goto out;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	case UI_SET_FFBIT:
94662306a36Sopenharmony_ci		retval = uinput_set_bit(arg, ffbit, FF_MAX);
94762306a36Sopenharmony_ci		goto out;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	case UI_SET_SWBIT:
95062306a36Sopenharmony_ci		retval = uinput_set_bit(arg, swbit, SW_MAX);
95162306a36Sopenharmony_ci		goto out;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	case UI_SET_PROPBIT:
95462306a36Sopenharmony_ci		retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
95562306a36Sopenharmony_ci		goto out;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	case UI_SET_PHYS:
95862306a36Sopenharmony_ci		if (udev->state == UIST_CREATED) {
95962306a36Sopenharmony_ci			retval = -EINVAL;
96062306a36Sopenharmony_ci			goto out;
96162306a36Sopenharmony_ci		}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci		phys = strndup_user(p, 1024);
96462306a36Sopenharmony_ci		if (IS_ERR(phys)) {
96562306a36Sopenharmony_ci			retval = PTR_ERR(phys);
96662306a36Sopenharmony_ci			goto out;
96762306a36Sopenharmony_ci		}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		kfree(udev->dev->phys);
97062306a36Sopenharmony_ci		udev->dev->phys = phys;
97162306a36Sopenharmony_ci		goto out;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	case UI_BEGIN_FF_UPLOAD:
97462306a36Sopenharmony_ci		retval = uinput_ff_upload_from_user(p, &ff_up);
97562306a36Sopenharmony_ci		if (retval)
97662306a36Sopenharmony_ci			goto out;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		req = uinput_request_find(udev, ff_up.request_id);
97962306a36Sopenharmony_ci		if (!req || req->code != UI_FF_UPLOAD ||
98062306a36Sopenharmony_ci		    !req->u.upload.effect) {
98162306a36Sopenharmony_ci			retval = -EINVAL;
98262306a36Sopenharmony_ci			goto out;
98362306a36Sopenharmony_ci		}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci		ff_up.retval = 0;
98662306a36Sopenharmony_ci		ff_up.effect = *req->u.upload.effect;
98762306a36Sopenharmony_ci		if (req->u.upload.old)
98862306a36Sopenharmony_ci			ff_up.old = *req->u.upload.old;
98962306a36Sopenharmony_ci		else
99062306a36Sopenharmony_ci			memset(&ff_up.old, 0, sizeof(struct ff_effect));
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		retval = uinput_ff_upload_to_user(p, &ff_up);
99362306a36Sopenharmony_ci		goto out;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	case UI_BEGIN_FF_ERASE:
99662306a36Sopenharmony_ci		if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
99762306a36Sopenharmony_ci			retval = -EFAULT;
99862306a36Sopenharmony_ci			goto out;
99962306a36Sopenharmony_ci		}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci		req = uinput_request_find(udev, ff_erase.request_id);
100262306a36Sopenharmony_ci		if (!req || req->code != UI_FF_ERASE) {
100362306a36Sopenharmony_ci			retval = -EINVAL;
100462306a36Sopenharmony_ci			goto out;
100562306a36Sopenharmony_ci		}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci		ff_erase.retval = 0;
100862306a36Sopenharmony_ci		ff_erase.effect_id = req->u.effect_id;
100962306a36Sopenharmony_ci		if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
101062306a36Sopenharmony_ci			retval = -EFAULT;
101162306a36Sopenharmony_ci			goto out;
101262306a36Sopenharmony_ci		}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci		goto out;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	case UI_END_FF_UPLOAD:
101762306a36Sopenharmony_ci		retval = uinput_ff_upload_from_user(p, &ff_up);
101862306a36Sopenharmony_ci		if (retval)
101962306a36Sopenharmony_ci			goto out;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci		req = uinput_request_find(udev, ff_up.request_id);
102262306a36Sopenharmony_ci		if (!req || req->code != UI_FF_UPLOAD ||
102362306a36Sopenharmony_ci		    !req->u.upload.effect) {
102462306a36Sopenharmony_ci			retval = -EINVAL;
102562306a36Sopenharmony_ci			goto out;
102662306a36Sopenharmony_ci		}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci		req->retval = ff_up.retval;
102962306a36Sopenharmony_ci		complete(&req->done);
103062306a36Sopenharmony_ci		goto out;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	case UI_END_FF_ERASE:
103362306a36Sopenharmony_ci		if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
103462306a36Sopenharmony_ci			retval = -EFAULT;
103562306a36Sopenharmony_ci			goto out;
103662306a36Sopenharmony_ci		}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci		req = uinput_request_find(udev, ff_erase.request_id);
103962306a36Sopenharmony_ci		if (!req || req->code != UI_FF_ERASE) {
104062306a36Sopenharmony_ci			retval = -EINVAL;
104162306a36Sopenharmony_ci			goto out;
104262306a36Sopenharmony_ci		}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci		req->retval = ff_erase.retval;
104562306a36Sopenharmony_ci		complete(&req->done);
104662306a36Sopenharmony_ci		goto out;
104762306a36Sopenharmony_ci	}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	size = _IOC_SIZE(cmd);
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	/* Now check variable-length commands */
105262306a36Sopenharmony_ci	switch (cmd & ~IOCSIZE_MASK) {
105362306a36Sopenharmony_ci	case UI_GET_SYSNAME(0):
105462306a36Sopenharmony_ci		if (udev->state != UIST_CREATED) {
105562306a36Sopenharmony_ci			retval = -ENOENT;
105662306a36Sopenharmony_ci			goto out;
105762306a36Sopenharmony_ci		}
105862306a36Sopenharmony_ci		name = dev_name(&udev->dev->dev);
105962306a36Sopenharmony_ci		retval = uinput_str_to_user(p, name, size);
106062306a36Sopenharmony_ci		goto out;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	case UI_ABS_SETUP & ~IOCSIZE_MASK:
106362306a36Sopenharmony_ci		retval = uinput_abs_setup(udev, p, size);
106462306a36Sopenharmony_ci		goto out;
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	retval = -EINVAL;
106862306a36Sopenharmony_ci out:
106962306a36Sopenharmony_ci	mutex_unlock(&udev->mutex);
107062306a36Sopenharmony_ci	return retval;
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_cistatic long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	return uinput_ioctl_handler(file, cmd, arg, (void __user *)arg);
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci/*
108162306a36Sopenharmony_ci * These IOCTLs change their size and thus their numbers between
108262306a36Sopenharmony_ci * 32 and 64 bits.
108362306a36Sopenharmony_ci */
108462306a36Sopenharmony_ci#define UI_SET_PHYS_COMPAT		\
108562306a36Sopenharmony_ci	_IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t)
108662306a36Sopenharmony_ci#define UI_BEGIN_FF_UPLOAD_COMPAT	\
108762306a36Sopenharmony_ci	_IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload_compat)
108862306a36Sopenharmony_ci#define UI_END_FF_UPLOAD_COMPAT		\
108962306a36Sopenharmony_ci	_IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload_compat)
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_cistatic long uinput_compat_ioctl(struct file *file,
109262306a36Sopenharmony_ci				unsigned int cmd, unsigned long arg)
109362306a36Sopenharmony_ci{
109462306a36Sopenharmony_ci	switch (cmd) {
109562306a36Sopenharmony_ci	case UI_SET_PHYS_COMPAT:
109662306a36Sopenharmony_ci		cmd = UI_SET_PHYS;
109762306a36Sopenharmony_ci		break;
109862306a36Sopenharmony_ci	case UI_BEGIN_FF_UPLOAD_COMPAT:
109962306a36Sopenharmony_ci		cmd = UI_BEGIN_FF_UPLOAD;
110062306a36Sopenharmony_ci		break;
110162306a36Sopenharmony_ci	case UI_END_FF_UPLOAD_COMPAT:
110262306a36Sopenharmony_ci		cmd = UI_END_FF_UPLOAD;
110362306a36Sopenharmony_ci		break;
110462306a36Sopenharmony_ci	}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg));
110762306a36Sopenharmony_ci}
110862306a36Sopenharmony_ci#endif
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_cistatic const struct file_operations uinput_fops = {
111162306a36Sopenharmony_ci	.owner		= THIS_MODULE,
111262306a36Sopenharmony_ci	.open		= uinput_open,
111362306a36Sopenharmony_ci	.release	= uinput_release,
111462306a36Sopenharmony_ci	.read		= uinput_read,
111562306a36Sopenharmony_ci	.write		= uinput_write,
111662306a36Sopenharmony_ci	.poll		= uinput_poll,
111762306a36Sopenharmony_ci	.unlocked_ioctl	= uinput_ioctl,
111862306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
111962306a36Sopenharmony_ci	.compat_ioctl	= uinput_compat_ioctl,
112062306a36Sopenharmony_ci#endif
112162306a36Sopenharmony_ci	.llseek		= no_llseek,
112262306a36Sopenharmony_ci};
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_cistatic struct miscdevice uinput_misc = {
112562306a36Sopenharmony_ci	.fops		= &uinput_fops,
112662306a36Sopenharmony_ci	.minor		= UINPUT_MINOR,
112762306a36Sopenharmony_ci	.name		= UINPUT_NAME,
112862306a36Sopenharmony_ci};
112962306a36Sopenharmony_cimodule_misc_device(uinput_misc);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ciMODULE_ALIAS_MISCDEV(UINPUT_MINOR);
113262306a36Sopenharmony_ciMODULE_ALIAS("devname:" UINPUT_NAME);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ciMODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
113562306a36Sopenharmony_ciMODULE_DESCRIPTION("User level driver support for input subsystem");
113662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1137