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