18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  User level driver support for input subsystem
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Heavily based on evdev.c by Vojtech Pavlik
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Changes/Revisions:
108c2ecf20Sopenharmony_ci *	0.4	01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
118c2ecf20Sopenharmony_ci *		- add UI_GET_SYSNAME ioctl
128c2ecf20Sopenharmony_ci *	0.3	09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>)
138c2ecf20Sopenharmony_ci *		- updated ff support for the changes in kernel interface
148c2ecf20Sopenharmony_ci *		- added MODULE_VERSION
158c2ecf20Sopenharmony_ci *	0.2	16/10/2004 (Micah Dowty <micah@navi.cx>)
168c2ecf20Sopenharmony_ci *		- added force feedback support
178c2ecf20Sopenharmony_ci *              - added UI_SET_PHYS
188c2ecf20Sopenharmony_ci *	0.1	20/06/2002
198c2ecf20Sopenharmony_ci *		- first public version
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci#include <uapi/linux/uinput.h>
228c2ecf20Sopenharmony_ci#include <linux/poll.h>
238c2ecf20Sopenharmony_ci#include <linux/sched.h>
248c2ecf20Sopenharmony_ci#include <linux/slab.h>
258c2ecf20Sopenharmony_ci#include <linux/module.h>
268c2ecf20Sopenharmony_ci#include <linux/init.h>
278c2ecf20Sopenharmony_ci#include <linux/fs.h>
288c2ecf20Sopenharmony_ci#include <linux/miscdevice.h>
298c2ecf20Sopenharmony_ci#include <linux/overflow.h>
308c2ecf20Sopenharmony_ci#include <linux/input/mt.h>
318c2ecf20Sopenharmony_ci#include "../input-compat.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define UINPUT_NAME		"uinput"
348c2ecf20Sopenharmony_ci#define UINPUT_BUFFER_SIZE	16
358c2ecf20Sopenharmony_ci#define UINPUT_NUM_REQUESTS	16
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cienum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED };
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistruct uinput_request {
408c2ecf20Sopenharmony_ci	unsigned int		id;
418c2ecf20Sopenharmony_ci	unsigned int		code;	/* UI_FF_UPLOAD, UI_FF_ERASE */
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	int			retval;
448c2ecf20Sopenharmony_ci	struct completion	done;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	union {
478c2ecf20Sopenharmony_ci		unsigned int	effect_id;
488c2ecf20Sopenharmony_ci		struct {
498c2ecf20Sopenharmony_ci			struct ff_effect *effect;
508c2ecf20Sopenharmony_ci			struct ff_effect *old;
518c2ecf20Sopenharmony_ci		} upload;
528c2ecf20Sopenharmony_ci	} u;
538c2ecf20Sopenharmony_ci};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistruct uinput_device {
568c2ecf20Sopenharmony_ci	struct input_dev	*dev;
578c2ecf20Sopenharmony_ci	struct mutex		mutex;
588c2ecf20Sopenharmony_ci	enum uinput_state	state;
598c2ecf20Sopenharmony_ci	wait_queue_head_t	waitq;
608c2ecf20Sopenharmony_ci	unsigned char		ready;
618c2ecf20Sopenharmony_ci	unsigned char		head;
628c2ecf20Sopenharmony_ci	unsigned char		tail;
638c2ecf20Sopenharmony_ci	struct input_event	buff[UINPUT_BUFFER_SIZE];
648c2ecf20Sopenharmony_ci	unsigned int		ff_effects_max;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	struct uinput_request	*requests[UINPUT_NUM_REQUESTS];
678c2ecf20Sopenharmony_ci	wait_queue_head_t	requests_waitq;
688c2ecf20Sopenharmony_ci	spinlock_t		requests_lock;
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic int uinput_dev_event(struct input_dev *dev,
728c2ecf20Sopenharmony_ci			    unsigned int type, unsigned int code, int value)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct uinput_device	*udev = input_get_drvdata(dev);
758c2ecf20Sopenharmony_ci	struct timespec64	ts;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	ktime_get_ts64(&ts);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	udev->buff[udev->head] = (struct input_event) {
808c2ecf20Sopenharmony_ci		.input_event_sec = ts.tv_sec,
818c2ecf20Sopenharmony_ci		.input_event_usec = ts.tv_nsec / NSEC_PER_USEC,
828c2ecf20Sopenharmony_ci		.type = type,
838c2ecf20Sopenharmony_ci		.code = code,
848c2ecf20Sopenharmony_ci		.value = value,
858c2ecf20Sopenharmony_ci	};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	wake_up_interruptible(&udev->waitq);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	return 0;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/* Atomically allocate an ID for the given request. Returns 0 on success. */
958c2ecf20Sopenharmony_cistatic bool uinput_request_alloc_id(struct uinput_device *udev,
968c2ecf20Sopenharmony_ci				    struct uinput_request *request)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	unsigned int id;
998c2ecf20Sopenharmony_ci	bool reserved = false;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	spin_lock(&udev->requests_lock);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	for (id = 0; id < UINPUT_NUM_REQUESTS; id++) {
1048c2ecf20Sopenharmony_ci		if (!udev->requests[id]) {
1058c2ecf20Sopenharmony_ci			request->id = id;
1068c2ecf20Sopenharmony_ci			udev->requests[id] = request;
1078c2ecf20Sopenharmony_ci			reserved = true;
1088c2ecf20Sopenharmony_ci			break;
1098c2ecf20Sopenharmony_ci		}
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	spin_unlock(&udev->requests_lock);
1138c2ecf20Sopenharmony_ci	return reserved;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic struct uinput_request *uinput_request_find(struct uinput_device *udev,
1178c2ecf20Sopenharmony_ci						  unsigned int id)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	/* Find an input request, by ID. Returns NULL if the ID isn't valid. */
1208c2ecf20Sopenharmony_ci	if (id >= UINPUT_NUM_REQUESTS)
1218c2ecf20Sopenharmony_ci		return NULL;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	return udev->requests[id];
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic int uinput_request_reserve_slot(struct uinput_device *udev,
1278c2ecf20Sopenharmony_ci				       struct uinput_request *request)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	/* Allocate slot. If none are available right away, wait. */
1308c2ecf20Sopenharmony_ci	return wait_event_interruptible(udev->requests_waitq,
1318c2ecf20Sopenharmony_ci					uinput_request_alloc_id(udev, request));
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic void uinput_request_release_slot(struct uinput_device *udev,
1358c2ecf20Sopenharmony_ci					unsigned int id)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	/* Mark slot as available */
1388c2ecf20Sopenharmony_ci	spin_lock(&udev->requests_lock);
1398c2ecf20Sopenharmony_ci	udev->requests[id] = NULL;
1408c2ecf20Sopenharmony_ci	spin_unlock(&udev->requests_lock);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	wake_up(&udev->requests_waitq);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic int uinput_request_send(struct uinput_device *udev,
1468c2ecf20Sopenharmony_ci			       struct uinput_request *request)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	int retval;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	retval = mutex_lock_interruptible(&udev->mutex);
1518c2ecf20Sopenharmony_ci	if (retval)
1528c2ecf20Sopenharmony_ci		return retval;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (udev->state != UIST_CREATED) {
1558c2ecf20Sopenharmony_ci		retval = -ENODEV;
1568c2ecf20Sopenharmony_ci		goto out;
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	init_completion(&request->done);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/*
1628c2ecf20Sopenharmony_ci	 * Tell our userspace application about this new request
1638c2ecf20Sopenharmony_ci	 * by queueing an input event.
1648c2ecf20Sopenharmony_ci	 */
1658c2ecf20Sopenharmony_ci	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci out:
1688c2ecf20Sopenharmony_ci	mutex_unlock(&udev->mutex);
1698c2ecf20Sopenharmony_ci	return retval;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic int uinput_request_submit(struct uinput_device *udev,
1738c2ecf20Sopenharmony_ci				 struct uinput_request *request)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	int retval;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	retval = uinput_request_reserve_slot(udev, request);
1788c2ecf20Sopenharmony_ci	if (retval)
1798c2ecf20Sopenharmony_ci		return retval;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	retval = uinput_request_send(udev, request);
1828c2ecf20Sopenharmony_ci	if (retval)
1838c2ecf20Sopenharmony_ci		goto out;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&request->done, 30 * HZ)) {
1868c2ecf20Sopenharmony_ci		retval = -ETIMEDOUT;
1878c2ecf20Sopenharmony_ci		goto out;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	retval = request->retval;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci out:
1938c2ecf20Sopenharmony_ci	uinput_request_release_slot(udev, request->id);
1948c2ecf20Sopenharmony_ci	return retval;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci/*
1988c2ecf20Sopenharmony_ci * Fail all outstanding requests so handlers don't wait for the userspace
1998c2ecf20Sopenharmony_ci * to finish processing them.
2008c2ecf20Sopenharmony_ci */
2018c2ecf20Sopenharmony_cistatic void uinput_flush_requests(struct uinput_device *udev)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	struct uinput_request *request;
2048c2ecf20Sopenharmony_ci	int i;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	spin_lock(&udev->requests_lock);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	for (i = 0; i < UINPUT_NUM_REQUESTS; i++) {
2098c2ecf20Sopenharmony_ci		request = udev->requests[i];
2108c2ecf20Sopenharmony_ci		if (request) {
2118c2ecf20Sopenharmony_ci			request->retval = -ENODEV;
2128c2ecf20Sopenharmony_ci			complete(&request->done);
2138c2ecf20Sopenharmony_ci		}
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	spin_unlock(&udev->requests_lock);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic void uinput_dev_set_gain(struct input_dev *dev, u16 gain)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	uinput_dev_event(dev, EV_FF, FF_GAIN, gain);
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude);
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic int uinput_dev_playback(struct input_dev *dev, int effect_id, int value)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	return uinput_dev_event(dev, EV_FF, effect_id, value);
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic int uinput_dev_upload_effect(struct input_dev *dev,
2358c2ecf20Sopenharmony_ci				    struct ff_effect *effect,
2368c2ecf20Sopenharmony_ci				    struct ff_effect *old)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct uinput_device *udev = input_get_drvdata(dev);
2398c2ecf20Sopenharmony_ci	struct uinput_request request;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	/*
2428c2ecf20Sopenharmony_ci	 * uinput driver does not currently support periodic effects with
2438c2ecf20Sopenharmony_ci	 * custom waveform since it does not have a way to pass buffer of
2448c2ecf20Sopenharmony_ci	 * samples (custom_data) to userspace. If ever there is a device
2458c2ecf20Sopenharmony_ci	 * supporting custom waveforms we would need to define an additional
2468c2ecf20Sopenharmony_ci	 * ioctl (UI_UPLOAD_SAMPLES) but for now we just bail out.
2478c2ecf20Sopenharmony_ci	 */
2488c2ecf20Sopenharmony_ci	if (effect->type == FF_PERIODIC &&
2498c2ecf20Sopenharmony_ci			effect->u.periodic.waveform == FF_CUSTOM)
2508c2ecf20Sopenharmony_ci		return -EINVAL;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	request.code = UI_FF_UPLOAD;
2538c2ecf20Sopenharmony_ci	request.u.upload.effect = effect;
2548c2ecf20Sopenharmony_ci	request.u.upload.old = old;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	return uinput_request_submit(udev, &request);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	struct uinput_device *udev = input_get_drvdata(dev);
2628c2ecf20Sopenharmony_ci	struct uinput_request request;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (!test_bit(EV_FF, dev->evbit))
2658c2ecf20Sopenharmony_ci		return -ENOSYS;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	request.code = UI_FF_ERASE;
2688c2ecf20Sopenharmony_ci	request.u.effect_id = effect_id;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	return uinput_request_submit(udev, &request);
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int uinput_dev_flush(struct input_dev *dev, struct file *file)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	/*
2768c2ecf20Sopenharmony_ci	 * If we are called with file == NULL that means we are tearing
2778c2ecf20Sopenharmony_ci	 * down the device, and therefore we can not handle FF erase
2788c2ecf20Sopenharmony_ci	 * requests: either we are handling UI_DEV_DESTROY (and holding
2798c2ecf20Sopenharmony_ci	 * the udev->mutex), or the file descriptor is closed and there is
2808c2ecf20Sopenharmony_ci	 * nobody on the other side anymore.
2818c2ecf20Sopenharmony_ci	 */
2828c2ecf20Sopenharmony_ci	return file ? input_ff_flush(dev, file) : 0;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic void uinput_destroy_device(struct uinput_device *udev)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	const char *name, *phys;
2888c2ecf20Sopenharmony_ci	struct input_dev *dev = udev->dev;
2898c2ecf20Sopenharmony_ci	enum uinput_state old_state = udev->state;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	udev->state = UIST_NEW_DEVICE;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (dev) {
2948c2ecf20Sopenharmony_ci		name = dev->name;
2958c2ecf20Sopenharmony_ci		phys = dev->phys;
2968c2ecf20Sopenharmony_ci		if (old_state == UIST_CREATED) {
2978c2ecf20Sopenharmony_ci			uinput_flush_requests(udev);
2988c2ecf20Sopenharmony_ci			input_unregister_device(dev);
2998c2ecf20Sopenharmony_ci		} else {
3008c2ecf20Sopenharmony_ci			input_free_device(dev);
3018c2ecf20Sopenharmony_ci		}
3028c2ecf20Sopenharmony_ci		kfree(name);
3038c2ecf20Sopenharmony_ci		kfree(phys);
3048c2ecf20Sopenharmony_ci		udev->dev = NULL;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic int uinput_create_device(struct uinput_device *udev)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	struct input_dev *dev = udev->dev;
3118c2ecf20Sopenharmony_ci	int error, nslot;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	if (udev->state != UIST_SETUP_COMPLETE) {
3148c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
3158c2ecf20Sopenharmony_ci		return -EINVAL;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (test_bit(EV_ABS, dev->evbit)) {
3198c2ecf20Sopenharmony_ci		input_alloc_absinfo(dev);
3208c2ecf20Sopenharmony_ci		if (!dev->absinfo) {
3218c2ecf20Sopenharmony_ci			error = -EINVAL;
3228c2ecf20Sopenharmony_ci			goto fail1;
3238c2ecf20Sopenharmony_ci		}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		if (test_bit(ABS_MT_SLOT, dev->absbit)) {
3268c2ecf20Sopenharmony_ci			nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
3278c2ecf20Sopenharmony_ci			error = input_mt_init_slots(dev, nslot, 0);
3288c2ecf20Sopenharmony_ci			if (error)
3298c2ecf20Sopenharmony_ci				goto fail1;
3308c2ecf20Sopenharmony_ci		} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
3318c2ecf20Sopenharmony_ci			input_set_events_per_packet(dev, 60);
3328c2ecf20Sopenharmony_ci		}
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (test_bit(EV_FF, dev->evbit) && !udev->ff_effects_max) {
3368c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: ff_effects_max should be non-zero when FF_BIT is set\n",
3378c2ecf20Sopenharmony_ci			UINPUT_NAME);
3388c2ecf20Sopenharmony_ci		error = -EINVAL;
3398c2ecf20Sopenharmony_ci		goto fail1;
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (udev->ff_effects_max) {
3438c2ecf20Sopenharmony_ci		error = input_ff_create(dev, udev->ff_effects_max);
3448c2ecf20Sopenharmony_ci		if (error)
3458c2ecf20Sopenharmony_ci			goto fail1;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		dev->ff->upload = uinput_dev_upload_effect;
3488c2ecf20Sopenharmony_ci		dev->ff->erase = uinput_dev_erase_effect;
3498c2ecf20Sopenharmony_ci		dev->ff->playback = uinput_dev_playback;
3508c2ecf20Sopenharmony_ci		dev->ff->set_gain = uinput_dev_set_gain;
3518c2ecf20Sopenharmony_ci		dev->ff->set_autocenter = uinput_dev_set_autocenter;
3528c2ecf20Sopenharmony_ci		/*
3538c2ecf20Sopenharmony_ci		 * The standard input_ff_flush() implementation does
3548c2ecf20Sopenharmony_ci		 * not quite work for uinput as we can't reasonably
3558c2ecf20Sopenharmony_ci		 * handle FF requests during device teardown.
3568c2ecf20Sopenharmony_ci		 */
3578c2ecf20Sopenharmony_ci		dev->flush = uinput_dev_flush;
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	dev->event = uinput_dev_event;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	input_set_drvdata(udev->dev, udev);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	error = input_register_device(udev->dev);
3658c2ecf20Sopenharmony_ci	if (error)
3668c2ecf20Sopenharmony_ci		goto fail2;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	udev->state = UIST_CREATED;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	return 0;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci fail2:	input_ff_destroy(dev);
3738c2ecf20Sopenharmony_ci fail1: uinput_destroy_device(udev);
3748c2ecf20Sopenharmony_ci	return error;
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cistatic int uinput_open(struct inode *inode, struct file *file)
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	struct uinput_device *newdev;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	newdev = kzalloc(sizeof(struct uinput_device), GFP_KERNEL);
3828c2ecf20Sopenharmony_ci	if (!newdev)
3838c2ecf20Sopenharmony_ci		return -ENOMEM;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	mutex_init(&newdev->mutex);
3868c2ecf20Sopenharmony_ci	spin_lock_init(&newdev->requests_lock);
3878c2ecf20Sopenharmony_ci	init_waitqueue_head(&newdev->requests_waitq);
3888c2ecf20Sopenharmony_ci	init_waitqueue_head(&newdev->waitq);
3898c2ecf20Sopenharmony_ci	newdev->state = UIST_NEW_DEVICE;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	file->private_data = newdev;
3928c2ecf20Sopenharmony_ci	stream_open(inode, file);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return 0;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,
3988c2ecf20Sopenharmony_ci				   const struct input_absinfo *abs)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	int min, max, range;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	min = abs->minimum;
4038c2ecf20Sopenharmony_ci	max = abs->maximum;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	if ((min != 0 || max != 0) && max < min) {
4068c2ecf20Sopenharmony_ci		printk(KERN_DEBUG
4078c2ecf20Sopenharmony_ci		       "%s: invalid abs[%02x] min:%d max:%d\n",
4088c2ecf20Sopenharmony_ci		       UINPUT_NAME, code, min, max);
4098c2ecf20Sopenharmony_ci		return -EINVAL;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (!check_sub_overflow(max, min, &range) && abs->flat > range) {
4138c2ecf20Sopenharmony_ci		printk(KERN_DEBUG
4148c2ecf20Sopenharmony_ci		       "%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",
4158c2ecf20Sopenharmony_ci		       UINPUT_NAME, code, abs->flat, min, max);
4168c2ecf20Sopenharmony_ci		return -EINVAL;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	/*
4208c2ecf20Sopenharmony_ci	 * Limit number of contacts to a reasonable value (100). This
4218c2ecf20Sopenharmony_ci	 * ensures that we need less than 2 pages for struct input_mt
4228c2ecf20Sopenharmony_ci	 * (we are not using in-kernel slot assignment so not going to
4238c2ecf20Sopenharmony_ci	 * allocate memory for the "red" table), and we should have no
4248c2ecf20Sopenharmony_ci	 * trouble getting this much memory.
4258c2ecf20Sopenharmony_ci	 */
4268c2ecf20Sopenharmony_ci	if (code == ABS_MT_SLOT && max > 99) {
4278c2ecf20Sopenharmony_ci		printk(KERN_DEBUG
4288c2ecf20Sopenharmony_ci		       "%s: unreasonably large number of slots requested: %d\n",
4298c2ecf20Sopenharmony_ci		       UINPUT_NAME, max);
4308c2ecf20Sopenharmony_ci		return -EINVAL;
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return 0;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic int uinput_validate_absbits(struct input_dev *dev)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	unsigned int cnt;
4398c2ecf20Sopenharmony_ci	int error;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	if (!test_bit(EV_ABS, dev->evbit))
4428c2ecf20Sopenharmony_ci		return 0;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	/*
4458c2ecf20Sopenharmony_ci	 * Check if absmin/absmax/absfuzz/absflat are sane.
4468c2ecf20Sopenharmony_ci	 */
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	for_each_set_bit(cnt, dev->absbit, ABS_CNT) {
4498c2ecf20Sopenharmony_ci		if (!dev->absinfo)
4508c2ecf20Sopenharmony_ci			return -EINVAL;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci		error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]);
4538c2ecf20Sopenharmony_ci		if (error)
4548c2ecf20Sopenharmony_ci			return error;
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	return 0;
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic int uinput_dev_setup(struct uinput_device *udev,
4618c2ecf20Sopenharmony_ci			    struct uinput_setup __user *arg)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	struct uinput_setup setup;
4648c2ecf20Sopenharmony_ci	struct input_dev *dev;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	if (udev->state == UIST_CREATED)
4678c2ecf20Sopenharmony_ci		return -EINVAL;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	if (copy_from_user(&setup, arg, sizeof(setup)))
4708c2ecf20Sopenharmony_ci		return -EFAULT;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (!setup.name[0])
4738c2ecf20Sopenharmony_ci		return -EINVAL;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	dev = udev->dev;
4768c2ecf20Sopenharmony_ci	dev->id = setup.id;
4778c2ecf20Sopenharmony_ci	udev->ff_effects_max = setup.ff_effects_max;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	kfree(dev->name);
4808c2ecf20Sopenharmony_ci	dev->name = kstrndup(setup.name, UINPUT_MAX_NAME_SIZE, GFP_KERNEL);
4818c2ecf20Sopenharmony_ci	if (!dev->name)
4828c2ecf20Sopenharmony_ci		return -ENOMEM;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	udev->state = UIST_SETUP_COMPLETE;
4858c2ecf20Sopenharmony_ci	return 0;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cistatic int uinput_abs_setup(struct uinput_device *udev,
4898c2ecf20Sopenharmony_ci			    struct uinput_setup __user *arg, size_t size)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	struct uinput_abs_setup setup = {};
4928c2ecf20Sopenharmony_ci	struct input_dev *dev;
4938c2ecf20Sopenharmony_ci	int error;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if (size > sizeof(setup))
4968c2ecf20Sopenharmony_ci		return -E2BIG;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	if (udev->state == UIST_CREATED)
4998c2ecf20Sopenharmony_ci		return -EINVAL;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	if (copy_from_user(&setup, arg, size))
5028c2ecf20Sopenharmony_ci		return -EFAULT;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	if (setup.code > ABS_MAX)
5058c2ecf20Sopenharmony_ci		return -ERANGE;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	dev = udev->dev;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	error = uinput_validate_absinfo(dev, setup.code, &setup.absinfo);
5108c2ecf20Sopenharmony_ci	if (error)
5118c2ecf20Sopenharmony_ci		return error;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	input_alloc_absinfo(dev);
5148c2ecf20Sopenharmony_ci	if (!dev->absinfo)
5158c2ecf20Sopenharmony_ci		return -ENOMEM;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	set_bit(setup.code, dev->absbit);
5188c2ecf20Sopenharmony_ci	dev->absinfo[setup.code] = setup.absinfo;
5198c2ecf20Sopenharmony_ci	return 0;
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci/* legacy setup via write() */
5238c2ecf20Sopenharmony_cistatic int uinput_setup_device_legacy(struct uinput_device *udev,
5248c2ecf20Sopenharmony_ci				      const char __user *buffer, size_t count)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	struct uinput_user_dev	*user_dev;
5278c2ecf20Sopenharmony_ci	struct input_dev	*dev;
5288c2ecf20Sopenharmony_ci	int			i;
5298c2ecf20Sopenharmony_ci	int			retval;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	if (count != sizeof(struct uinput_user_dev))
5328c2ecf20Sopenharmony_ci		return -EINVAL;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	if (!udev->dev) {
5358c2ecf20Sopenharmony_ci		udev->dev = input_allocate_device();
5368c2ecf20Sopenharmony_ci		if (!udev->dev)
5378c2ecf20Sopenharmony_ci			return -ENOMEM;
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	dev = udev->dev;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev));
5438c2ecf20Sopenharmony_ci	if (IS_ERR(user_dev))
5448c2ecf20Sopenharmony_ci		return PTR_ERR(user_dev);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	udev->ff_effects_max = user_dev->ff_effects_max;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	/* Ensure name is filled in */
5498c2ecf20Sopenharmony_ci	if (!user_dev->name[0]) {
5508c2ecf20Sopenharmony_ci		retval = -EINVAL;
5518c2ecf20Sopenharmony_ci		goto exit;
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	kfree(dev->name);
5558c2ecf20Sopenharmony_ci	dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE,
5568c2ecf20Sopenharmony_ci			     GFP_KERNEL);
5578c2ecf20Sopenharmony_ci	if (!dev->name) {
5588c2ecf20Sopenharmony_ci		retval = -ENOMEM;
5598c2ecf20Sopenharmony_ci		goto exit;
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	dev->id.bustype	= user_dev->id.bustype;
5638c2ecf20Sopenharmony_ci	dev->id.vendor	= user_dev->id.vendor;
5648c2ecf20Sopenharmony_ci	dev->id.product	= user_dev->id.product;
5658c2ecf20Sopenharmony_ci	dev->id.version	= user_dev->id.version;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	for (i = 0; i < ABS_CNT; i++) {
5688c2ecf20Sopenharmony_ci		input_abs_set_max(dev, i, user_dev->absmax[i]);
5698c2ecf20Sopenharmony_ci		input_abs_set_min(dev, i, user_dev->absmin[i]);
5708c2ecf20Sopenharmony_ci		input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]);
5718c2ecf20Sopenharmony_ci		input_abs_set_flat(dev, i, user_dev->absflat[i]);
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	retval = uinput_validate_absbits(dev);
5758c2ecf20Sopenharmony_ci	if (retval < 0)
5768c2ecf20Sopenharmony_ci		goto exit;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	udev->state = UIST_SETUP_COMPLETE;
5798c2ecf20Sopenharmony_ci	retval = count;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci exit:
5828c2ecf20Sopenharmony_ci	kfree(user_dev);
5838c2ecf20Sopenharmony_ci	return retval;
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic ssize_t uinput_inject_events(struct uinput_device *udev,
5878c2ecf20Sopenharmony_ci				    const char __user *buffer, size_t count)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	struct input_event ev;
5908c2ecf20Sopenharmony_ci	size_t bytes = 0;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	if (count != 0 && count < input_event_size())
5938c2ecf20Sopenharmony_ci		return -EINVAL;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	while (bytes + input_event_size() <= count) {
5968c2ecf20Sopenharmony_ci		/*
5978c2ecf20Sopenharmony_ci		 * Note that even if some events were fetched successfully
5988c2ecf20Sopenharmony_ci		 * we are still going to return EFAULT instead of partial
5998c2ecf20Sopenharmony_ci		 * count to let userspace know that it got it's buffers
6008c2ecf20Sopenharmony_ci		 * all wrong.
6018c2ecf20Sopenharmony_ci		 */
6028c2ecf20Sopenharmony_ci		if (input_event_from_user(buffer + bytes, &ev))
6038c2ecf20Sopenharmony_ci			return -EFAULT;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci		input_event(udev->dev, ev.type, ev.code, ev.value);
6068c2ecf20Sopenharmony_ci		bytes += input_event_size();
6078c2ecf20Sopenharmony_ci		cond_resched();
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	return bytes;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic ssize_t uinput_write(struct file *file, const char __user *buffer,
6148c2ecf20Sopenharmony_ci			    size_t count, loff_t *ppos)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	struct uinput_device *udev = file->private_data;
6178c2ecf20Sopenharmony_ci	int retval;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	if (count == 0)
6208c2ecf20Sopenharmony_ci		return 0;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	retval = mutex_lock_interruptible(&udev->mutex);
6238c2ecf20Sopenharmony_ci	if (retval)
6248c2ecf20Sopenharmony_ci		return retval;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	retval = udev->state == UIST_CREATED ?
6278c2ecf20Sopenharmony_ci			uinput_inject_events(udev, buffer, count) :
6288c2ecf20Sopenharmony_ci			uinput_setup_device_legacy(udev, buffer, count);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	mutex_unlock(&udev->mutex);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	return retval;
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic bool uinput_fetch_next_event(struct uinput_device *udev,
6368c2ecf20Sopenharmony_ci				    struct input_event *event)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	bool have_event;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	spin_lock_irq(&udev->dev->event_lock);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	have_event = udev->head != udev->tail;
6438c2ecf20Sopenharmony_ci	if (have_event) {
6448c2ecf20Sopenharmony_ci		*event = udev->buff[udev->tail];
6458c2ecf20Sopenharmony_ci		udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	spin_unlock_irq(&udev->dev->event_lock);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	return have_event;
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistatic ssize_t uinput_events_to_user(struct uinput_device *udev,
6548c2ecf20Sopenharmony_ci				     char __user *buffer, size_t count)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	struct input_event event;
6578c2ecf20Sopenharmony_ci	size_t read = 0;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	while (read + input_event_size() <= count &&
6608c2ecf20Sopenharmony_ci	       uinput_fetch_next_event(udev, &event)) {
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci		if (input_event_to_user(buffer + read, &event))
6638c2ecf20Sopenharmony_ci			return -EFAULT;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci		read += input_event_size();
6668c2ecf20Sopenharmony_ci	}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	return read;
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic ssize_t uinput_read(struct file *file, char __user *buffer,
6728c2ecf20Sopenharmony_ci			   size_t count, loff_t *ppos)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	struct uinput_device *udev = file->private_data;
6758c2ecf20Sopenharmony_ci	ssize_t retval;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	if (count != 0 && count < input_event_size())
6788c2ecf20Sopenharmony_ci		return -EINVAL;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	do {
6818c2ecf20Sopenharmony_ci		retval = mutex_lock_interruptible(&udev->mutex);
6828c2ecf20Sopenharmony_ci		if (retval)
6838c2ecf20Sopenharmony_ci			return retval;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		if (udev->state != UIST_CREATED)
6868c2ecf20Sopenharmony_ci			retval = -ENODEV;
6878c2ecf20Sopenharmony_ci		else if (udev->head == udev->tail &&
6888c2ecf20Sopenharmony_ci			 (file->f_flags & O_NONBLOCK))
6898c2ecf20Sopenharmony_ci			retval = -EAGAIN;
6908c2ecf20Sopenharmony_ci		else
6918c2ecf20Sopenharmony_ci			retval = uinput_events_to_user(udev, buffer, count);
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci		mutex_unlock(&udev->mutex);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci		if (retval || count == 0)
6968c2ecf20Sopenharmony_ci			break;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci		if (!(file->f_flags & O_NONBLOCK))
6998c2ecf20Sopenharmony_ci			retval = wait_event_interruptible(udev->waitq,
7008c2ecf20Sopenharmony_ci						  udev->head != udev->tail ||
7018c2ecf20Sopenharmony_ci						  udev->state != UIST_CREATED);
7028c2ecf20Sopenharmony_ci	} while (retval == 0);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	return retval;
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_cistatic __poll_t uinput_poll(struct file *file, poll_table *wait)
7088c2ecf20Sopenharmony_ci{
7098c2ecf20Sopenharmony_ci	struct uinput_device *udev = file->private_data;
7108c2ecf20Sopenharmony_ci	__poll_t mask = EPOLLOUT | EPOLLWRNORM; /* uinput is always writable */
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	poll_wait(file, &udev->waitq, wait);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	if (udev->head != udev->tail)
7158c2ecf20Sopenharmony_ci		mask |= EPOLLIN | EPOLLRDNORM;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	return mask;
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic int uinput_release(struct inode *inode, struct file *file)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	struct uinput_device *udev = file->private_data;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	uinput_destroy_device(udev);
7258c2ecf20Sopenharmony_ci	kfree(udev);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	return 0;
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
7318c2ecf20Sopenharmony_cistruct uinput_ff_upload_compat {
7328c2ecf20Sopenharmony_ci	__u32			request_id;
7338c2ecf20Sopenharmony_ci	__s32			retval;
7348c2ecf20Sopenharmony_ci	struct ff_effect_compat	effect;
7358c2ecf20Sopenharmony_ci	struct ff_effect_compat	old;
7368c2ecf20Sopenharmony_ci};
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_cistatic int uinput_ff_upload_to_user(char __user *buffer,
7398c2ecf20Sopenharmony_ci				    const struct uinput_ff_upload *ff_up)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	if (in_compat_syscall()) {
7428c2ecf20Sopenharmony_ci		struct uinput_ff_upload_compat ff_up_compat;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci		ff_up_compat.request_id = ff_up->request_id;
7458c2ecf20Sopenharmony_ci		ff_up_compat.retval = ff_up->retval;
7468c2ecf20Sopenharmony_ci		/*
7478c2ecf20Sopenharmony_ci		 * It so happens that the pointer that gives us the trouble
7488c2ecf20Sopenharmony_ci		 * is the last field in the structure. Since we don't support
7498c2ecf20Sopenharmony_ci		 * custom waveforms in uinput anyway we can just copy the whole
7508c2ecf20Sopenharmony_ci		 * thing (to the compat size) and ignore the pointer.
7518c2ecf20Sopenharmony_ci		 */
7528c2ecf20Sopenharmony_ci		memcpy(&ff_up_compat.effect, &ff_up->effect,
7538c2ecf20Sopenharmony_ci			sizeof(struct ff_effect_compat));
7548c2ecf20Sopenharmony_ci		memcpy(&ff_up_compat.old, &ff_up->old,
7558c2ecf20Sopenharmony_ci			sizeof(struct ff_effect_compat));
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci		if (copy_to_user(buffer, &ff_up_compat,
7588c2ecf20Sopenharmony_ci				 sizeof(struct uinput_ff_upload_compat)))
7598c2ecf20Sopenharmony_ci			return -EFAULT;
7608c2ecf20Sopenharmony_ci	} else {
7618c2ecf20Sopenharmony_ci		if (copy_to_user(buffer, ff_up,
7628c2ecf20Sopenharmony_ci				 sizeof(struct uinput_ff_upload)))
7638c2ecf20Sopenharmony_ci			return -EFAULT;
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	return 0;
7678c2ecf20Sopenharmony_ci}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_cistatic int uinput_ff_upload_from_user(const char __user *buffer,
7708c2ecf20Sopenharmony_ci				      struct uinput_ff_upload *ff_up)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	if (in_compat_syscall()) {
7738c2ecf20Sopenharmony_ci		struct uinput_ff_upload_compat ff_up_compat;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci		if (copy_from_user(&ff_up_compat, buffer,
7768c2ecf20Sopenharmony_ci				   sizeof(struct uinput_ff_upload_compat)))
7778c2ecf20Sopenharmony_ci			return -EFAULT;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci		ff_up->request_id = ff_up_compat.request_id;
7808c2ecf20Sopenharmony_ci		ff_up->retval = ff_up_compat.retval;
7818c2ecf20Sopenharmony_ci		memcpy(&ff_up->effect, &ff_up_compat.effect,
7828c2ecf20Sopenharmony_ci			sizeof(struct ff_effect_compat));
7838c2ecf20Sopenharmony_ci		memcpy(&ff_up->old, &ff_up_compat.old,
7848c2ecf20Sopenharmony_ci			sizeof(struct ff_effect_compat));
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	} else {
7878c2ecf20Sopenharmony_ci		if (copy_from_user(ff_up, buffer,
7888c2ecf20Sopenharmony_ci				   sizeof(struct uinput_ff_upload)))
7898c2ecf20Sopenharmony_ci			return -EFAULT;
7908c2ecf20Sopenharmony_ci	}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	return 0;
7938c2ecf20Sopenharmony_ci}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci#else
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cistatic int uinput_ff_upload_to_user(char __user *buffer,
7988c2ecf20Sopenharmony_ci				    const struct uinput_ff_upload *ff_up)
7998c2ecf20Sopenharmony_ci{
8008c2ecf20Sopenharmony_ci	if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload)))
8018c2ecf20Sopenharmony_ci		return -EFAULT;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	return 0;
8048c2ecf20Sopenharmony_ci}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_cistatic int uinput_ff_upload_from_user(const char __user *buffer,
8078c2ecf20Sopenharmony_ci				      struct uinput_ff_upload *ff_up)
8088c2ecf20Sopenharmony_ci{
8098c2ecf20Sopenharmony_ci	if (copy_from_user(ff_up, buffer, sizeof(struct uinput_ff_upload)))
8108c2ecf20Sopenharmony_ci		return -EFAULT;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	return 0;
8138c2ecf20Sopenharmony_ci}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci#endif
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci#define uinput_set_bit(_arg, _bit, _max)		\
8188c2ecf20Sopenharmony_ci({							\
8198c2ecf20Sopenharmony_ci	int __ret = 0;					\
8208c2ecf20Sopenharmony_ci	if (udev->state == UIST_CREATED)		\
8218c2ecf20Sopenharmony_ci		__ret =  -EINVAL;			\
8228c2ecf20Sopenharmony_ci	else if ((_arg) > (_max))			\
8238c2ecf20Sopenharmony_ci		__ret = -EINVAL;			\
8248c2ecf20Sopenharmony_ci	else set_bit((_arg), udev->dev->_bit);		\
8258c2ecf20Sopenharmony_ci	__ret;						\
8268c2ecf20Sopenharmony_ci})
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cistatic int uinput_str_to_user(void __user *dest, const char *str,
8298c2ecf20Sopenharmony_ci			      unsigned int maxlen)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	char __user *p = dest;
8328c2ecf20Sopenharmony_ci	int len, ret;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	if (!str)
8358c2ecf20Sopenharmony_ci		return -ENOENT;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	if (maxlen == 0)
8388c2ecf20Sopenharmony_ci		return -EINVAL;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	len = strlen(str) + 1;
8418c2ecf20Sopenharmony_ci	if (len > maxlen)
8428c2ecf20Sopenharmony_ci		len = maxlen;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	ret = copy_to_user(p, str, len);
8458c2ecf20Sopenharmony_ci	if (ret)
8468c2ecf20Sopenharmony_ci		return -EFAULT;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	/* force terminating '\0' */
8498c2ecf20Sopenharmony_ci	ret = put_user(0, p + len - 1);
8508c2ecf20Sopenharmony_ci	return ret ? -EFAULT : len;
8518c2ecf20Sopenharmony_ci}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_cistatic long uinput_ioctl_handler(struct file *file, unsigned int cmd,
8548c2ecf20Sopenharmony_ci				 unsigned long arg, void __user *p)
8558c2ecf20Sopenharmony_ci{
8568c2ecf20Sopenharmony_ci	int			retval;
8578c2ecf20Sopenharmony_ci	struct uinput_device	*udev = file->private_data;
8588c2ecf20Sopenharmony_ci	struct uinput_ff_upload ff_up;
8598c2ecf20Sopenharmony_ci	struct uinput_ff_erase  ff_erase;
8608c2ecf20Sopenharmony_ci	struct uinput_request   *req;
8618c2ecf20Sopenharmony_ci	char			*phys;
8628c2ecf20Sopenharmony_ci	const char		*name;
8638c2ecf20Sopenharmony_ci	unsigned int		size;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	retval = mutex_lock_interruptible(&udev->mutex);
8668c2ecf20Sopenharmony_ci	if (retval)
8678c2ecf20Sopenharmony_ci		return retval;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	if (!udev->dev) {
8708c2ecf20Sopenharmony_ci		udev->dev = input_allocate_device();
8718c2ecf20Sopenharmony_ci		if (!udev->dev) {
8728c2ecf20Sopenharmony_ci			retval = -ENOMEM;
8738c2ecf20Sopenharmony_ci			goto out;
8748c2ecf20Sopenharmony_ci		}
8758c2ecf20Sopenharmony_ci	}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	switch (cmd) {
8788c2ecf20Sopenharmony_ci	case UI_GET_VERSION:
8798c2ecf20Sopenharmony_ci		if (put_user(UINPUT_VERSION, (unsigned int __user *)p))
8808c2ecf20Sopenharmony_ci			retval = -EFAULT;
8818c2ecf20Sopenharmony_ci		goto out;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	case UI_DEV_CREATE:
8848c2ecf20Sopenharmony_ci		retval = uinput_create_device(udev);
8858c2ecf20Sopenharmony_ci		goto out;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	case UI_DEV_DESTROY:
8888c2ecf20Sopenharmony_ci		uinput_destroy_device(udev);
8898c2ecf20Sopenharmony_ci		goto out;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	case UI_DEV_SETUP:
8928c2ecf20Sopenharmony_ci		retval = uinput_dev_setup(udev, p);
8938c2ecf20Sopenharmony_ci		goto out;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	/* UI_ABS_SETUP is handled in the variable size ioctls */
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	case UI_SET_EVBIT:
8988c2ecf20Sopenharmony_ci		retval = uinput_set_bit(arg, evbit, EV_MAX);
8998c2ecf20Sopenharmony_ci		goto out;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	case UI_SET_KEYBIT:
9028c2ecf20Sopenharmony_ci		retval = uinput_set_bit(arg, keybit, KEY_MAX);
9038c2ecf20Sopenharmony_ci		goto out;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	case UI_SET_RELBIT:
9068c2ecf20Sopenharmony_ci		retval = uinput_set_bit(arg, relbit, REL_MAX);
9078c2ecf20Sopenharmony_ci		goto out;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	case UI_SET_ABSBIT:
9108c2ecf20Sopenharmony_ci		retval = uinput_set_bit(arg, absbit, ABS_MAX);
9118c2ecf20Sopenharmony_ci		goto out;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	case UI_SET_MSCBIT:
9148c2ecf20Sopenharmony_ci		retval = uinput_set_bit(arg, mscbit, MSC_MAX);
9158c2ecf20Sopenharmony_ci		goto out;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	case UI_SET_LEDBIT:
9188c2ecf20Sopenharmony_ci		retval = uinput_set_bit(arg, ledbit, LED_MAX);
9198c2ecf20Sopenharmony_ci		goto out;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	case UI_SET_SNDBIT:
9228c2ecf20Sopenharmony_ci		retval = uinput_set_bit(arg, sndbit, SND_MAX);
9238c2ecf20Sopenharmony_ci		goto out;
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	case UI_SET_FFBIT:
9268c2ecf20Sopenharmony_ci		retval = uinput_set_bit(arg, ffbit, FF_MAX);
9278c2ecf20Sopenharmony_ci		goto out;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	case UI_SET_SWBIT:
9308c2ecf20Sopenharmony_ci		retval = uinput_set_bit(arg, swbit, SW_MAX);
9318c2ecf20Sopenharmony_ci		goto out;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	case UI_SET_PROPBIT:
9348c2ecf20Sopenharmony_ci		retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
9358c2ecf20Sopenharmony_ci		goto out;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	case UI_SET_PHYS:
9388c2ecf20Sopenharmony_ci		if (udev->state == UIST_CREATED) {
9398c2ecf20Sopenharmony_ci			retval = -EINVAL;
9408c2ecf20Sopenharmony_ci			goto out;
9418c2ecf20Sopenharmony_ci		}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci		phys = strndup_user(p, 1024);
9448c2ecf20Sopenharmony_ci		if (IS_ERR(phys)) {
9458c2ecf20Sopenharmony_ci			retval = PTR_ERR(phys);
9468c2ecf20Sopenharmony_ci			goto out;
9478c2ecf20Sopenharmony_ci		}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci		kfree(udev->dev->phys);
9508c2ecf20Sopenharmony_ci		udev->dev->phys = phys;
9518c2ecf20Sopenharmony_ci		goto out;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	case UI_BEGIN_FF_UPLOAD:
9548c2ecf20Sopenharmony_ci		retval = uinput_ff_upload_from_user(p, &ff_up);
9558c2ecf20Sopenharmony_ci		if (retval)
9568c2ecf20Sopenharmony_ci			goto out;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci		req = uinput_request_find(udev, ff_up.request_id);
9598c2ecf20Sopenharmony_ci		if (!req || req->code != UI_FF_UPLOAD ||
9608c2ecf20Sopenharmony_ci		    !req->u.upload.effect) {
9618c2ecf20Sopenharmony_ci			retval = -EINVAL;
9628c2ecf20Sopenharmony_ci			goto out;
9638c2ecf20Sopenharmony_ci		}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci		ff_up.retval = 0;
9668c2ecf20Sopenharmony_ci		ff_up.effect = *req->u.upload.effect;
9678c2ecf20Sopenharmony_ci		if (req->u.upload.old)
9688c2ecf20Sopenharmony_ci			ff_up.old = *req->u.upload.old;
9698c2ecf20Sopenharmony_ci		else
9708c2ecf20Sopenharmony_ci			memset(&ff_up.old, 0, sizeof(struct ff_effect));
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci		retval = uinput_ff_upload_to_user(p, &ff_up);
9738c2ecf20Sopenharmony_ci		goto out;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	case UI_BEGIN_FF_ERASE:
9768c2ecf20Sopenharmony_ci		if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
9778c2ecf20Sopenharmony_ci			retval = -EFAULT;
9788c2ecf20Sopenharmony_ci			goto out;
9798c2ecf20Sopenharmony_ci		}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci		req = uinput_request_find(udev, ff_erase.request_id);
9828c2ecf20Sopenharmony_ci		if (!req || req->code != UI_FF_ERASE) {
9838c2ecf20Sopenharmony_ci			retval = -EINVAL;
9848c2ecf20Sopenharmony_ci			goto out;
9858c2ecf20Sopenharmony_ci		}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci		ff_erase.retval = 0;
9888c2ecf20Sopenharmony_ci		ff_erase.effect_id = req->u.effect_id;
9898c2ecf20Sopenharmony_ci		if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
9908c2ecf20Sopenharmony_ci			retval = -EFAULT;
9918c2ecf20Sopenharmony_ci			goto out;
9928c2ecf20Sopenharmony_ci		}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci		goto out;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	case UI_END_FF_UPLOAD:
9978c2ecf20Sopenharmony_ci		retval = uinput_ff_upload_from_user(p, &ff_up);
9988c2ecf20Sopenharmony_ci		if (retval)
9998c2ecf20Sopenharmony_ci			goto out;
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci		req = uinput_request_find(udev, ff_up.request_id);
10028c2ecf20Sopenharmony_ci		if (!req || req->code != UI_FF_UPLOAD ||
10038c2ecf20Sopenharmony_ci		    !req->u.upload.effect) {
10048c2ecf20Sopenharmony_ci			retval = -EINVAL;
10058c2ecf20Sopenharmony_ci			goto out;
10068c2ecf20Sopenharmony_ci		}
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci		req->retval = ff_up.retval;
10098c2ecf20Sopenharmony_ci		complete(&req->done);
10108c2ecf20Sopenharmony_ci		goto out;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	case UI_END_FF_ERASE:
10138c2ecf20Sopenharmony_ci		if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
10148c2ecf20Sopenharmony_ci			retval = -EFAULT;
10158c2ecf20Sopenharmony_ci			goto out;
10168c2ecf20Sopenharmony_ci		}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci		req = uinput_request_find(udev, ff_erase.request_id);
10198c2ecf20Sopenharmony_ci		if (!req || req->code != UI_FF_ERASE) {
10208c2ecf20Sopenharmony_ci			retval = -EINVAL;
10218c2ecf20Sopenharmony_ci			goto out;
10228c2ecf20Sopenharmony_ci		}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci		req->retval = ff_erase.retval;
10258c2ecf20Sopenharmony_ci		complete(&req->done);
10268c2ecf20Sopenharmony_ci		goto out;
10278c2ecf20Sopenharmony_ci	}
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	size = _IOC_SIZE(cmd);
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	/* Now check variable-length commands */
10328c2ecf20Sopenharmony_ci	switch (cmd & ~IOCSIZE_MASK) {
10338c2ecf20Sopenharmony_ci	case UI_GET_SYSNAME(0):
10348c2ecf20Sopenharmony_ci		if (udev->state != UIST_CREATED) {
10358c2ecf20Sopenharmony_ci			retval = -ENOENT;
10368c2ecf20Sopenharmony_ci			goto out;
10378c2ecf20Sopenharmony_ci		}
10388c2ecf20Sopenharmony_ci		name = dev_name(&udev->dev->dev);
10398c2ecf20Sopenharmony_ci		retval = uinput_str_to_user(p, name, size);
10408c2ecf20Sopenharmony_ci		goto out;
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	case UI_ABS_SETUP & ~IOCSIZE_MASK:
10438c2ecf20Sopenharmony_ci		retval = uinput_abs_setup(udev, p, size);
10448c2ecf20Sopenharmony_ci		goto out;
10458c2ecf20Sopenharmony_ci	}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	retval = -EINVAL;
10488c2ecf20Sopenharmony_ci out:
10498c2ecf20Sopenharmony_ci	mutex_unlock(&udev->mutex);
10508c2ecf20Sopenharmony_ci	return retval;
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_cistatic long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
10548c2ecf20Sopenharmony_ci{
10558c2ecf20Sopenharmony_ci	return uinput_ioctl_handler(file, cmd, arg, (void __user *)arg);
10568c2ecf20Sopenharmony_ci}
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci/*
10618c2ecf20Sopenharmony_ci * These IOCTLs change their size and thus their numbers between
10628c2ecf20Sopenharmony_ci * 32 and 64 bits.
10638c2ecf20Sopenharmony_ci */
10648c2ecf20Sopenharmony_ci#define UI_SET_PHYS_COMPAT		\
10658c2ecf20Sopenharmony_ci	_IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t)
10668c2ecf20Sopenharmony_ci#define UI_BEGIN_FF_UPLOAD_COMPAT	\
10678c2ecf20Sopenharmony_ci	_IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload_compat)
10688c2ecf20Sopenharmony_ci#define UI_END_FF_UPLOAD_COMPAT		\
10698c2ecf20Sopenharmony_ci	_IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload_compat)
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_cistatic long uinput_compat_ioctl(struct file *file,
10728c2ecf20Sopenharmony_ci				unsigned int cmd, unsigned long arg)
10738c2ecf20Sopenharmony_ci{
10748c2ecf20Sopenharmony_ci	switch (cmd) {
10758c2ecf20Sopenharmony_ci	case UI_SET_PHYS_COMPAT:
10768c2ecf20Sopenharmony_ci		cmd = UI_SET_PHYS;
10778c2ecf20Sopenharmony_ci		break;
10788c2ecf20Sopenharmony_ci	case UI_BEGIN_FF_UPLOAD_COMPAT:
10798c2ecf20Sopenharmony_ci		cmd = UI_BEGIN_FF_UPLOAD;
10808c2ecf20Sopenharmony_ci		break;
10818c2ecf20Sopenharmony_ci	case UI_END_FF_UPLOAD_COMPAT:
10828c2ecf20Sopenharmony_ci		cmd = UI_END_FF_UPLOAD;
10838c2ecf20Sopenharmony_ci		break;
10848c2ecf20Sopenharmony_ci	}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg));
10878c2ecf20Sopenharmony_ci}
10888c2ecf20Sopenharmony_ci#endif
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_cistatic const struct file_operations uinput_fops = {
10918c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
10928c2ecf20Sopenharmony_ci	.open		= uinput_open,
10938c2ecf20Sopenharmony_ci	.release	= uinput_release,
10948c2ecf20Sopenharmony_ci	.read		= uinput_read,
10958c2ecf20Sopenharmony_ci	.write		= uinput_write,
10968c2ecf20Sopenharmony_ci	.poll		= uinput_poll,
10978c2ecf20Sopenharmony_ci	.unlocked_ioctl	= uinput_ioctl,
10988c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
10998c2ecf20Sopenharmony_ci	.compat_ioctl	= uinput_compat_ioctl,
11008c2ecf20Sopenharmony_ci#endif
11018c2ecf20Sopenharmony_ci	.llseek		= no_llseek,
11028c2ecf20Sopenharmony_ci};
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_cistatic struct miscdevice uinput_misc = {
11058c2ecf20Sopenharmony_ci	.fops		= &uinput_fops,
11068c2ecf20Sopenharmony_ci	.minor		= UINPUT_MINOR,
11078c2ecf20Sopenharmony_ci	.name		= UINPUT_NAME,
11088c2ecf20Sopenharmony_ci};
11098c2ecf20Sopenharmony_cimodule_misc_device(uinput_misc);
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ciMODULE_ALIAS_MISCDEV(UINPUT_MINOR);
11128c2ecf20Sopenharmony_ciMODULE_ALIAS("devname:" UINPUT_NAME);
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ciMODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
11158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("User level driver support for input subsystem");
11168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1117