1136 lines · 25.3 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* *  User level driver support for input subsystem * * Heavily based on evdev.c by Vojtech Pavlik * * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> * * Changes/Revisions: *	0.4	01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>) *		- add UI_GET_SYSNAME ioctl *	0.3	09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>) *		- updated ff support for the changes in kernel interface *		- added MODULE_VERSION *	0.2	16/10/2004 (Micah Dowty <micah@navi.cx>) *		- added force feedback support *              - added UI_SET_PHYS *	0.1	20/06/2002 *		- first public version */#include <uapi/linux/uinput.h>#include <linux/poll.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/overflow.h>#include <linux/input/mt.h>#include "../input-compat.h" #define UINPUT_NAME		"uinput"#define UINPUT_BUFFER_SIZE	16#define UINPUT_NUM_REQUESTS	16#define UINPUT_TIMESTAMP_ALLOWED_OFFSET_SECS 10 enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED }; struct uinput_request {	unsigned int		id;	unsigned int		code;	/* UI_FF_UPLOAD, UI_FF_ERASE */ 	int			retval;	struct completion	done; 	union {		unsigned int	effect_id;		struct {			struct ff_effect *effect;			struct ff_effect *old;		} upload;	} u;}; struct uinput_device {	struct input_dev	*dev;	struct mutex		mutex;	enum uinput_state	state;	wait_queue_head_t	waitq;	unsigned char		ready;	unsigned char		head;	unsigned char		tail;	struct input_event	buff[UINPUT_BUFFER_SIZE];	unsigned int		ff_effects_max; 	struct uinput_request	*requests[UINPUT_NUM_REQUESTS];	wait_queue_head_t	requests_waitq;	spinlock_t		requests_lock;}; static int uinput_dev_event(struct input_dev *dev,			    unsigned int type, unsigned int code, int value){	struct uinput_device	*udev = input_get_drvdata(dev);	struct timespec64	ts; 	ktime_get_ts64(&ts); 	udev->buff[udev->head] = (struct input_event) {		.input_event_sec = ts.tv_sec,		.input_event_usec = ts.tv_nsec / NSEC_PER_USEC,		.type = type,		.code = code,		.value = value,	}; 	udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE; 	wake_up_interruptible(&udev->waitq); 	return 0;} /* Atomically allocate an ID for the given request. Returns 0 on success. */static bool uinput_request_alloc_id(struct uinput_device *udev,				    struct uinput_request *request){	unsigned int id;	bool reserved = false; 	spin_lock(&udev->requests_lock); 	for (id = 0; id < UINPUT_NUM_REQUESTS; id++) {		if (!udev->requests[id]) {			request->id = id;			udev->requests[id] = request;			reserved = true;			break;		}	} 	spin_unlock(&udev->requests_lock);	return reserved;} static struct uinput_request *uinput_request_find(struct uinput_device *udev,						  unsigned int id){	/* Find an input request, by ID. Returns NULL if the ID isn't valid. */	if (id >= UINPUT_NUM_REQUESTS)		return NULL; 	return udev->requests[id];} static int uinput_request_reserve_slot(struct uinput_device *udev,				       struct uinput_request *request){	/* Allocate slot. If none are available right away, wait. */	return wait_event_interruptible(udev->requests_waitq,					uinput_request_alloc_id(udev, request));} static void uinput_request_release_slot(struct uinput_device *udev,					unsigned int id){	/* Mark slot as available */	spin_lock(&udev->requests_lock);	udev->requests[id] = NULL;	spin_unlock(&udev->requests_lock); 	wake_up(&udev->requests_waitq);} static int uinput_request_send(struct uinput_device *udev,			       struct uinput_request *request){	int retval; 	retval = mutex_lock_interruptible(&udev->mutex);	if (retval)		return retval; 	if (udev->state != UIST_CREATED) {		retval = -ENODEV;		goto out;	} 	init_completion(&request->done); 	/*	 * Tell our userspace application about this new request	 * by queueing an input event.	 */	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);  out:	mutex_unlock(&udev->mutex);	return retval;} static int uinput_request_submit(struct uinput_device *udev,				 struct uinput_request *request){	int retval; 	retval = uinput_request_reserve_slot(udev, request);	if (retval)		return retval; 	retval = uinput_request_send(udev, request);	if (retval)		goto out; 	if (!wait_for_completion_timeout(&request->done, 30 * HZ)) {		retval = -ETIMEDOUT;		goto out;	} 	retval = request->retval;  out:	uinput_request_release_slot(udev, request->id);	return retval;} /* * Fail all outstanding requests so handlers don't wait for the userspace * to finish processing them. */static void uinput_flush_requests(struct uinput_device *udev){	struct uinput_request *request;	int i; 	spin_lock(&udev->requests_lock); 	for (i = 0; i < UINPUT_NUM_REQUESTS; i++) {		request = udev->requests[i];		if (request) {			request->retval = -ENODEV;			complete(&request->done);		}	} 	spin_unlock(&udev->requests_lock);} static void uinput_dev_set_gain(struct input_dev *dev, u16 gain){	uinput_dev_event(dev, EV_FF, FF_GAIN, gain);} static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude){	uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude);} static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value){	return uinput_dev_event(dev, EV_FF, effect_id, value);} static int uinput_dev_upload_effect(struct input_dev *dev,				    struct ff_effect *effect,				    struct ff_effect *old){	struct uinput_device *udev = input_get_drvdata(dev);	struct uinput_request request; 	/*	 * uinput driver does not currently support periodic effects with	 * custom waveform since it does not have a way to pass buffer of	 * samples (custom_data) to userspace. If ever there is a device	 * supporting custom waveforms we would need to define an additional	 * ioctl (UI_UPLOAD_SAMPLES) but for now we just bail out.	 */	if (effect->type == FF_PERIODIC &&			effect->u.periodic.waveform == FF_CUSTOM)		return -EINVAL; 	request.code = UI_FF_UPLOAD;	request.u.upload.effect = effect;	request.u.upload.old = old; 	return uinput_request_submit(udev, &request);} static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id){	struct uinput_device *udev = input_get_drvdata(dev);	struct uinput_request request; 	if (!test_bit(EV_FF, dev->evbit))		return -ENOSYS; 	request.code = UI_FF_ERASE;	request.u.effect_id = effect_id; 	return uinput_request_submit(udev, &request);} static int uinput_dev_flush(struct input_dev *dev, struct file *file){	/*	 * If we are called with file == NULL that means we are tearing	 * down the device, and therefore we can not handle FF erase	 * requests: either we are handling UI_DEV_DESTROY (and holding	 * the udev->mutex), or the file descriptor is closed and there is	 * nobody on the other side anymore.	 */	return file ? input_ff_flush(dev, file) : 0;} static void uinput_destroy_device(struct uinput_device *udev){	const char *name, *phys;	struct input_dev *dev = udev->dev;	enum uinput_state old_state = udev->state; 	udev->state = UIST_NEW_DEVICE; 	if (dev) {		name = dev->name;		phys = dev->phys;		if (old_state == UIST_CREATED) {			uinput_flush_requests(udev);			input_unregister_device(dev);		} else {			input_free_device(dev);		}		kfree(name);		kfree(phys);		udev->dev = NULL;	}} static int uinput_create_device(struct uinput_device *udev){	struct input_dev *dev = udev->dev;	int error, nslot; 	if (udev->state != UIST_SETUP_COMPLETE) {		printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);		return -EINVAL;	} 	if (test_bit(EV_ABS, dev->evbit)) {		input_alloc_absinfo(dev);		if (!dev->absinfo) {			error = -EINVAL;			goto fail1;		} 		if (test_bit(ABS_MT_SLOT, dev->absbit)) {			nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;			error = input_mt_init_slots(dev, nslot, 0);			if (error)				goto fail1;		} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {			input_set_events_per_packet(dev, 60);		}	} 	if (test_bit(EV_FF, dev->evbit) && !udev->ff_effects_max) {		printk(KERN_DEBUG "%s: ff_effects_max should be non-zero when FF_BIT is set\n",			UINPUT_NAME);		error = -EINVAL;		goto fail1;	} 	if (udev->ff_effects_max) {		error = input_ff_create(dev, udev->ff_effects_max);		if (error)			goto fail1; 		dev->ff->upload = uinput_dev_upload_effect;		dev->ff->erase = uinput_dev_erase_effect;		dev->ff->playback = uinput_dev_playback;		dev->ff->set_gain = uinput_dev_set_gain;		dev->ff->set_autocenter = uinput_dev_set_autocenter;		/*		 * The standard input_ff_flush() implementation does		 * not quite work for uinput as we can't reasonably		 * handle FF requests during device teardown.		 */		dev->flush = uinput_dev_flush;	} 	dev->event = uinput_dev_event; 	input_set_drvdata(udev->dev, udev); 	error = input_register_device(udev->dev);	if (error)		goto fail2; 	udev->state = UIST_CREATED; 	return 0;  fail2:	input_ff_destroy(dev); fail1: uinput_destroy_device(udev);	return error;} static int uinput_open(struct inode *inode, struct file *file){	struct uinput_device *newdev; 	newdev = kzalloc(sizeof(struct uinput_device), GFP_KERNEL);	if (!newdev)		return -ENOMEM; 	mutex_init(&newdev->mutex);	spin_lock_init(&newdev->requests_lock);	init_waitqueue_head(&newdev->requests_waitq);	init_waitqueue_head(&newdev->waitq);	newdev->state = UIST_NEW_DEVICE; 	file->private_data = newdev;	stream_open(inode, file); 	return 0;} static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,				   const struct input_absinfo *abs){	int min, max, range; 	min = abs->minimum;	max = abs->maximum; 	if ((min != 0 || max != 0) && max < min) {		printk(KERN_DEBUG		       "%s: invalid abs[%02x] min:%d max:%d\n",		       UINPUT_NAME, code, min, max);		return -EINVAL;	} 	if (!check_sub_overflow(max, min, &range) && abs->flat > range) {		printk(KERN_DEBUG		       "%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",		       UINPUT_NAME, code, abs->flat, min, max);		return -EINVAL;	} 	return 0;} static int uinput_validate_absbits(struct input_dev *dev){	unsigned int cnt;	int error; 	if (!test_bit(EV_ABS, dev->evbit))		return 0; 	/*	 * Check if absmin/absmax/absfuzz/absflat are sane.	 */ 	for_each_set_bit(cnt, dev->absbit, ABS_CNT) {		if (!dev->absinfo)			return -EINVAL; 		error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]);		if (error)			return error;	} 	return 0;} static int uinput_dev_setup(struct uinput_device *udev,			    struct uinput_setup __user *arg){	struct uinput_setup setup;	struct input_dev *dev; 	if (udev->state == UIST_CREATED)		return -EINVAL; 	if (copy_from_user(&setup, arg, sizeof(setup)))		return -EFAULT; 	if (!setup.name[0])		return -EINVAL; 	dev = udev->dev;	dev->id = setup.id;	udev->ff_effects_max = setup.ff_effects_max; 	kfree(dev->name);	dev->name = kstrndup(setup.name, UINPUT_MAX_NAME_SIZE, GFP_KERNEL);	if (!dev->name)		return -ENOMEM; 	udev->state = UIST_SETUP_COMPLETE;	return 0;} static int uinput_abs_setup(struct uinput_device *udev,			    struct uinput_setup __user *arg, size_t size){	struct uinput_abs_setup setup = {};	struct input_dev *dev;	int error; 	if (size > sizeof(setup))		return -E2BIG; 	if (udev->state == UIST_CREATED)		return -EINVAL; 	if (copy_from_user(&setup, arg, size))		return -EFAULT; 	if (setup.code > ABS_MAX)		return -ERANGE; 	dev = udev->dev; 	error = uinput_validate_absinfo(dev, setup.code, &setup.absinfo);	if (error)		return error; 	input_alloc_absinfo(dev);

Lines 1–500 of 1136.