11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * User level driver support for input subsystem 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Heavily based on evdev.c by Vojtech Pavlik 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 81da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 91da177e4SLinus Torvalds * (at your option) any later version. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 121da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 131da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 141da177e4SLinus Torvalds * GNU General Public License for more details. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 171da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 181da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> 211da177e4SLinus Torvalds * 221da177e4SLinus Torvalds * Changes/Revisions: 23e3480a61SBenjamin Tissoires * 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>) 24e3480a61SBenjamin Tissoires * - add UI_GET_SYSNAME ioctl 25ff462551SAnssi Hannula * 0.3 09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>) 26ff462551SAnssi Hannula * - updated ff support for the changes in kernel interface 27ff462551SAnssi Hannula * - added MODULE_VERSION 281da177e4SLinus Torvalds * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) 291da177e4SLinus Torvalds * - added force feedback support 301da177e4SLinus Torvalds * - added UI_SET_PHYS 311da177e4SLinus Torvalds * 0.1 20/06/2002 321da177e4SLinus Torvalds * - first public version 331da177e4SLinus Torvalds */ 34a11bc476SDmitry Torokhov #include <uapi/linux/uinput.h> 351da177e4SLinus Torvalds #include <linux/poll.h> 36a99bbaf5SAlexey Dobriyan #include <linux/sched.h> 371da177e4SLinus Torvalds #include <linux/slab.h> 381da177e4SLinus Torvalds #include <linux/module.h> 391da177e4SLinus Torvalds #include <linux/init.h> 401da177e4SLinus Torvalds #include <linux/fs.h> 411da177e4SLinus Torvalds #include <linux/miscdevice.h> 42d77651a2SDmitry Torokhov #include <linux/overflow.h> 4347c78e89SHenrik Rydberg #include <linux/input/mt.h> 442d56f3a3SPhilip Langdale #include "../input-compat.h" 451da177e4SLinus Torvalds 46a11bc476SDmitry Torokhov #define UINPUT_NAME "uinput" 47a11bc476SDmitry Torokhov #define UINPUT_BUFFER_SIZE 16 48a11bc476SDmitry Torokhov #define UINPUT_NUM_REQUESTS 16 49a11bc476SDmitry Torokhov 50a11bc476SDmitry Torokhov enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED }; 51a11bc476SDmitry Torokhov 52a11bc476SDmitry Torokhov struct uinput_request { 53a11bc476SDmitry Torokhov unsigned int id; 54a11bc476SDmitry Torokhov unsigned int code; /* UI_FF_UPLOAD, UI_FF_ERASE */ 55a11bc476SDmitry Torokhov 56a11bc476SDmitry Torokhov int retval; 57a11bc476SDmitry Torokhov struct completion done; 58a11bc476SDmitry Torokhov 59a11bc476SDmitry Torokhov union { 60a11bc476SDmitry Torokhov unsigned int effect_id; 61a11bc476SDmitry Torokhov struct { 62a11bc476SDmitry Torokhov struct ff_effect *effect; 63a11bc476SDmitry Torokhov struct ff_effect *old; 64a11bc476SDmitry Torokhov } upload; 65a11bc476SDmitry Torokhov } u; 66a11bc476SDmitry Torokhov }; 67a11bc476SDmitry Torokhov 68a11bc476SDmitry Torokhov struct uinput_device { 69a11bc476SDmitry Torokhov struct input_dev *dev; 70a11bc476SDmitry Torokhov struct mutex mutex; 71a11bc476SDmitry Torokhov enum uinput_state state; 72a11bc476SDmitry Torokhov wait_queue_head_t waitq; 73a11bc476SDmitry Torokhov unsigned char ready; 74a11bc476SDmitry Torokhov unsigned char head; 75a11bc476SDmitry Torokhov unsigned char tail; 76a11bc476SDmitry Torokhov struct input_event buff[UINPUT_BUFFER_SIZE]; 77a11bc476SDmitry Torokhov unsigned int ff_effects_max; 78a11bc476SDmitry Torokhov 79a11bc476SDmitry Torokhov struct uinput_request *requests[UINPUT_NUM_REQUESTS]; 80a11bc476SDmitry Torokhov wait_queue_head_t requests_waitq; 81a11bc476SDmitry Torokhov spinlock_t requests_lock; 82a11bc476SDmitry Torokhov }; 83a11bc476SDmitry Torokhov 8454ce165eSDmitry Torokhov static int uinput_dev_event(struct input_dev *dev, 8554ce165eSDmitry Torokhov unsigned int type, unsigned int code, int value) 861da177e4SLinus Torvalds { 87373f9713SDmitry Torokhov struct uinput_device *udev = input_get_drvdata(dev); 88b3495cecSDeepa Dinamani struct timespec64 ts; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds udev->buff[udev->head].type = type; 911da177e4SLinus Torvalds udev->buff[udev->head].code = code; 921da177e4SLinus Torvalds udev->buff[udev->head].value = value; 93b3495cecSDeepa Dinamani ktime_get_ts64(&ts); 94152194feSDeepa Dinamani udev->buff[udev->head].input_event_sec = ts.tv_sec; 95152194feSDeepa Dinamani udev->buff[udev->head].input_event_usec = ts.tv_nsec / NSEC_PER_USEC; 961da177e4SLinus Torvalds udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE; 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds wake_up_interruptible(&udev->waitq); 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds return 0; 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 10305cebd38SAristeu Sergio Rozanski Filho /* Atomically allocate an ID for the given request. Returns 0 on success. */ 10400ce756cSDmitry Torokhov static bool uinput_request_alloc_id(struct uinput_device *udev, 10500ce756cSDmitry Torokhov struct uinput_request *request) 1061da177e4SLinus Torvalds { 107c5b3533aSDmitry Torokhov unsigned int id; 10800ce756cSDmitry Torokhov bool reserved = false; 1091da177e4SLinus Torvalds 1100048e603SDmitry Torokhov spin_lock(&udev->requests_lock); 111152c12f5SDmitry Torokhov 11205cebd38SAristeu Sergio Rozanski Filho for (id = 0; id < UINPUT_NUM_REQUESTS; id++) { 1131da177e4SLinus Torvalds if (!udev->requests[id]) { 1141da177e4SLinus Torvalds request->id = id; 1150048e603SDmitry Torokhov udev->requests[id] = request; 11600ce756cSDmitry Torokhov reserved = true; 117152c12f5SDmitry Torokhov break; 1181da177e4SLinus Torvalds } 11905cebd38SAristeu Sergio Rozanski Filho } 120152c12f5SDmitry Torokhov 1210048e603SDmitry Torokhov spin_unlock(&udev->requests_lock); 12200ce756cSDmitry Torokhov return reserved; 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds 125c5b3533aSDmitry Torokhov static struct uinput_request *uinput_request_find(struct uinput_device *udev, 126c5b3533aSDmitry Torokhov unsigned int id) 1271da177e4SLinus Torvalds { 1281da177e4SLinus Torvalds /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ 129c5b3533aSDmitry Torokhov if (id >= UINPUT_NUM_REQUESTS) 1301da177e4SLinus Torvalds return NULL; 1312d56f3a3SPhilip Langdale 1321da177e4SLinus Torvalds return udev->requests[id]; 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 13500ce756cSDmitry Torokhov static int uinput_request_reserve_slot(struct uinput_device *udev, 13600ce756cSDmitry Torokhov struct uinput_request *request) 1371da177e4SLinus Torvalds { 1380048e603SDmitry Torokhov /* Allocate slot. If none are available right away, wait. */ 1390048e603SDmitry Torokhov return wait_event_interruptible(udev->requests_waitq, 14000ce756cSDmitry Torokhov uinput_request_alloc_id(udev, request)); 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 1436b4877c7SDmitry Torokhov static void uinput_request_release_slot(struct uinput_device *udev, 1446b4877c7SDmitry Torokhov unsigned int id) 1451da177e4SLinus Torvalds { 1460048e603SDmitry Torokhov /* Mark slot as available */ 1476b4877c7SDmitry Torokhov spin_lock(&udev->requests_lock); 1486b4877c7SDmitry Torokhov udev->requests[id] = NULL; 1496b4877c7SDmitry Torokhov spin_unlock(&udev->requests_lock); 150e7507ed9SDmitry Torokhov 1516b4877c7SDmitry Torokhov wake_up(&udev->requests_waitq); 1520048e603SDmitry Torokhov } 1530048e603SDmitry Torokhov 15400ce756cSDmitry Torokhov static int uinput_request_send(struct uinput_device *udev, 15500ce756cSDmitry Torokhov struct uinput_request *request) 1560048e603SDmitry Torokhov { 15705cebd38SAristeu Sergio Rozanski Filho int retval; 1581da177e4SLinus Torvalds 15905cebd38SAristeu Sergio Rozanski Filho retval = mutex_lock_interruptible(&udev->mutex); 16005cebd38SAristeu Sergio Rozanski Filho if (retval) 16105cebd38SAristeu Sergio Rozanski Filho return retval; 16205cebd38SAristeu Sergio Rozanski Filho 16305cebd38SAristeu Sergio Rozanski Filho if (udev->state != UIST_CREATED) { 16405cebd38SAristeu Sergio Rozanski Filho retval = -ENODEV; 16505cebd38SAristeu Sergio Rozanski Filho goto out; 16605cebd38SAristeu Sergio Rozanski Filho } 16705cebd38SAristeu Sergio Rozanski Filho 16800ce756cSDmitry Torokhov init_completion(&request->done); 16900ce756cSDmitry Torokhov 17000ce756cSDmitry Torokhov /* 17100ce756cSDmitry Torokhov * Tell our userspace application about this new request 17200ce756cSDmitry Torokhov * by queueing an input event. 17300ce756cSDmitry Torokhov */ 17405cebd38SAristeu Sergio Rozanski Filho uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); 17505cebd38SAristeu Sergio Rozanski Filho 17605cebd38SAristeu Sergio Rozanski Filho out: 17705cebd38SAristeu Sergio Rozanski Filho mutex_unlock(&udev->mutex); 17805cebd38SAristeu Sergio Rozanski Filho return retval; 17905cebd38SAristeu Sergio Rozanski Filho } 18005cebd38SAristeu Sergio Rozanski Filho 18100ce756cSDmitry Torokhov static int uinput_request_submit(struct uinput_device *udev, 18200ce756cSDmitry Torokhov struct uinput_request *request) 18300ce756cSDmitry Torokhov { 1846b4877c7SDmitry Torokhov int retval; 18500ce756cSDmitry Torokhov 1866b4877c7SDmitry Torokhov retval = uinput_request_reserve_slot(udev, request); 1876b4877c7SDmitry Torokhov if (retval) 1886b4877c7SDmitry Torokhov return retval; 18900ce756cSDmitry Torokhov 1906b4877c7SDmitry Torokhov retval = uinput_request_send(udev, request); 1916b4877c7SDmitry Torokhov if (retval) 1926b4877c7SDmitry Torokhov goto out; 19300ce756cSDmitry Torokhov 1948e009118SDmitry Torokhov if (!wait_for_completion_timeout(&request->done, 30 * HZ)) { 1958e009118SDmitry Torokhov retval = -ETIMEDOUT; 1968e009118SDmitry Torokhov goto out; 1978e009118SDmitry Torokhov } 1988e009118SDmitry Torokhov 1996b4877c7SDmitry Torokhov retval = request->retval; 2006b4877c7SDmitry Torokhov 2016b4877c7SDmitry Torokhov out: 2026b4877c7SDmitry Torokhov uinput_request_release_slot(udev, request->id); 2036b4877c7SDmitry Torokhov return retval; 20400ce756cSDmitry Torokhov } 20500ce756cSDmitry Torokhov 20605cebd38SAristeu Sergio Rozanski Filho /* 20754ce165eSDmitry Torokhov * Fail all outstanding requests so handlers don't wait for the userspace 20805cebd38SAristeu Sergio Rozanski Filho * to finish processing them. 20905cebd38SAristeu Sergio Rozanski Filho */ 21005cebd38SAristeu Sergio Rozanski Filho static void uinput_flush_requests(struct uinput_device *udev) 21105cebd38SAristeu Sergio Rozanski Filho { 21205cebd38SAristeu Sergio Rozanski Filho struct uinput_request *request; 21305cebd38SAristeu Sergio Rozanski Filho int i; 21405cebd38SAristeu Sergio Rozanski Filho 21505cebd38SAristeu Sergio Rozanski Filho spin_lock(&udev->requests_lock); 21605cebd38SAristeu Sergio Rozanski Filho 21705cebd38SAristeu Sergio Rozanski Filho for (i = 0; i < UINPUT_NUM_REQUESTS; i++) { 21805cebd38SAristeu Sergio Rozanski Filho request = udev->requests[i]; 21905cebd38SAristeu Sergio Rozanski Filho if (request) { 22005cebd38SAristeu Sergio Rozanski Filho request->retval = -ENODEV; 2216b4877c7SDmitry Torokhov complete(&request->done); 22205cebd38SAristeu Sergio Rozanski Filho } 22305cebd38SAristeu Sergio Rozanski Filho } 22405cebd38SAristeu Sergio Rozanski Filho 22505cebd38SAristeu Sergio Rozanski Filho spin_unlock(&udev->requests_lock); 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds 228ff462551SAnssi Hannula static void uinput_dev_set_gain(struct input_dev *dev, u16 gain) 229ff462551SAnssi Hannula { 230ff462551SAnssi Hannula uinput_dev_event(dev, EV_FF, FF_GAIN, gain); 231ff462551SAnssi Hannula } 232ff462551SAnssi Hannula 233ff462551SAnssi Hannula static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude) 234ff462551SAnssi Hannula { 235ff462551SAnssi Hannula uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude); 236ff462551SAnssi Hannula } 237ff462551SAnssi Hannula 238ff462551SAnssi Hannula static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value) 239ff462551SAnssi Hannula { 240ff462551SAnssi Hannula return uinput_dev_event(dev, EV_FF, effect_id, value); 241ff462551SAnssi Hannula } 242ff462551SAnssi Hannula 24354ce165eSDmitry Torokhov static int uinput_dev_upload_effect(struct input_dev *dev, 24454ce165eSDmitry Torokhov struct ff_effect *effect, 24554ce165eSDmitry Torokhov struct ff_effect *old) 2461da177e4SLinus Torvalds { 24705cebd38SAristeu Sergio Rozanski Filho struct uinput_device *udev = input_get_drvdata(dev); 2481da177e4SLinus Torvalds struct uinput_request request; 2491da177e4SLinus Torvalds 2502d56f3a3SPhilip Langdale /* 2512d56f3a3SPhilip Langdale * uinput driver does not currently support periodic effects with 2522d56f3a3SPhilip Langdale * custom waveform since it does not have a way to pass buffer of 2532d56f3a3SPhilip Langdale * samples (custom_data) to userspace. If ever there is a device 2542d56f3a3SPhilip Langdale * supporting custom waveforms we would need to define an additional 2552d56f3a3SPhilip Langdale * ioctl (UI_UPLOAD_SAMPLES) but for now we just bail out. 2562d56f3a3SPhilip Langdale */ 2572d56f3a3SPhilip Langdale if (effect->type == FF_PERIODIC && 2582d56f3a3SPhilip Langdale effect->u.periodic.waveform == FF_CUSTOM) 2592d56f3a3SPhilip Langdale return -EINVAL; 2602d56f3a3SPhilip Langdale 2610048e603SDmitry Torokhov request.code = UI_FF_UPLOAD; 262ff462551SAnssi Hannula request.u.upload.effect = effect; 263ff462551SAnssi Hannula request.u.upload.old = old; 2640048e603SDmitry Torokhov 26500ce756cSDmitry Torokhov return uinput_request_submit(udev, &request); 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) 2691da177e4SLinus Torvalds { 27005cebd38SAristeu Sergio Rozanski Filho struct uinput_device *udev = input_get_drvdata(dev); 2711da177e4SLinus Torvalds struct uinput_request request; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds if (!test_bit(EV_FF, dev->evbit)) 2741da177e4SLinus Torvalds return -ENOSYS; 2751da177e4SLinus Torvalds 2760048e603SDmitry Torokhov request.code = UI_FF_ERASE; 2771da177e4SLinus Torvalds request.u.effect_id = effect_id; 2780048e603SDmitry Torokhov 27900ce756cSDmitry Torokhov return uinput_request_submit(udev, &request); 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 282e8b95728SDmitry Torokhov static int uinput_dev_flush(struct input_dev *dev, struct file *file) 283e8b95728SDmitry Torokhov { 284e8b95728SDmitry Torokhov /* 285e8b95728SDmitry Torokhov * If we are called with file == NULL that means we are tearing 286e8b95728SDmitry Torokhov * down the device, and therefore we can not handle FF erase 287e8b95728SDmitry Torokhov * requests: either we are handling UI_DEV_DESTROY (and holding 288e8b95728SDmitry Torokhov * the udev->mutex), or the file descriptor is closed and there is 289e8b95728SDmitry Torokhov * nobody on the other side anymore. 290e8b95728SDmitry Torokhov */ 291e8b95728SDmitry Torokhov return file ? input_ff_flush(dev, file) : 0; 292e8b95728SDmitry Torokhov } 293e8b95728SDmitry Torokhov 29429506415SDmitry Torokhov static void uinput_destroy_device(struct uinput_device *udev) 29529506415SDmitry Torokhov { 29629506415SDmitry Torokhov const char *name, *phys; 29705cebd38SAristeu Sergio Rozanski Filho struct input_dev *dev = udev->dev; 29805cebd38SAristeu Sergio Rozanski Filho enum uinput_state old_state = udev->state; 29929506415SDmitry Torokhov 30005cebd38SAristeu Sergio Rozanski Filho udev->state = UIST_NEW_DEVICE; 30105cebd38SAristeu Sergio Rozanski Filho 30205cebd38SAristeu Sergio Rozanski Filho if (dev) { 30305cebd38SAristeu Sergio Rozanski Filho name = dev->name; 30405cebd38SAristeu Sergio Rozanski Filho phys = dev->phys; 30505cebd38SAristeu Sergio Rozanski Filho if (old_state == UIST_CREATED) { 30605cebd38SAristeu Sergio Rozanski Filho uinput_flush_requests(udev); 30705cebd38SAristeu Sergio Rozanski Filho input_unregister_device(dev); 30805cebd38SAristeu Sergio Rozanski Filho } else { 30905cebd38SAristeu Sergio Rozanski Filho input_free_device(dev); 31005cebd38SAristeu Sergio Rozanski Filho } 31129506415SDmitry Torokhov kfree(name); 31229506415SDmitry Torokhov kfree(phys); 31329506415SDmitry Torokhov udev->dev = NULL; 31429506415SDmitry Torokhov } 31529506415SDmitry Torokhov } 31629506415SDmitry Torokhov 3171da177e4SLinus Torvalds static int uinput_create_device(struct uinput_device *udev) 3181da177e4SLinus Torvalds { 319ff462551SAnssi Hannula struct input_dev *dev = udev->dev; 320fbae10dbSDavid Herrmann int error, nslot; 32129506415SDmitry Torokhov 32229506415SDmitry Torokhov if (udev->state != UIST_SETUP_COMPLETE) { 3231da177e4SLinus Torvalds printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME); 3241da177e4SLinus Torvalds return -EINVAL; 3251da177e4SLinus Torvalds } 3261da177e4SLinus Torvalds 327601bbbe0SDmitry Torokhov if (test_bit(EV_ABS, dev->evbit)) { 328601bbbe0SDmitry Torokhov input_alloc_absinfo(dev); 329601bbbe0SDmitry Torokhov if (!dev->absinfo) { 330601bbbe0SDmitry Torokhov error = -EINVAL; 331601bbbe0SDmitry Torokhov goto fail1; 332601bbbe0SDmitry Torokhov } 333601bbbe0SDmitry Torokhov 334fbae10dbSDavid Herrmann if (test_bit(ABS_MT_SLOT, dev->absbit)) { 335fbae10dbSDavid Herrmann nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; 336fbae10dbSDavid Herrmann error = input_mt_init_slots(dev, nslot, 0); 337fbae10dbSDavid Herrmann if (error) 338fbae10dbSDavid Herrmann goto fail1; 339fbae10dbSDavid Herrmann } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { 340fbae10dbSDavid Herrmann input_set_events_per_packet(dev, 60); 341fbae10dbSDavid Herrmann } 342601bbbe0SDmitry Torokhov } 343fbae10dbSDavid Herrmann 344daf6cd0cSElias Vanderstuyft if (test_bit(EV_FF, dev->evbit) && !udev->ff_effects_max) { 345daf6cd0cSElias Vanderstuyft printk(KERN_DEBUG "%s: ff_effects_max should be non-zero when FF_BIT is set\n", 346daf6cd0cSElias Vanderstuyft UINPUT_NAME); 347daf6cd0cSElias Vanderstuyft error = -EINVAL; 348daf6cd0cSElias Vanderstuyft goto fail1; 349daf6cd0cSElias Vanderstuyft } 350daf6cd0cSElias Vanderstuyft 351ff462551SAnssi Hannula if (udev->ff_effects_max) { 352ff462551SAnssi Hannula error = input_ff_create(dev, udev->ff_effects_max); 353ff462551SAnssi Hannula if (error) 354ff462551SAnssi Hannula goto fail1; 355ff462551SAnssi Hannula 356ff462551SAnssi Hannula dev->ff->upload = uinput_dev_upload_effect; 357ff462551SAnssi Hannula dev->ff->erase = uinput_dev_erase_effect; 358ff462551SAnssi Hannula dev->ff->playback = uinput_dev_playback; 359ff462551SAnssi Hannula dev->ff->set_gain = uinput_dev_set_gain; 360ff462551SAnssi Hannula dev->ff->set_autocenter = uinput_dev_set_autocenter; 361e8b95728SDmitry Torokhov /* 362e8b95728SDmitry Torokhov * The standard input_ff_flush() implementation does 363e8b95728SDmitry Torokhov * not quite work for uinput as we can't reasonably 364e8b95728SDmitry Torokhov * handle FF requests during device teardown. 365e8b95728SDmitry Torokhov */ 366e8b95728SDmitry Torokhov dev->flush = uinput_dev_flush; 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 36904ce40a6SDmitry Torokhov dev->event = uinput_dev_event; 37004ce40a6SDmitry Torokhov 37104ce40a6SDmitry Torokhov input_set_drvdata(udev->dev, udev); 37204ce40a6SDmitry Torokhov 373ff462551SAnssi Hannula error = input_register_device(udev->dev); 374ff462551SAnssi Hannula if (error) 375ff462551SAnssi Hannula goto fail2; 376ff462551SAnssi Hannula 37729506415SDmitry Torokhov udev->state = UIST_CREATED; 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds return 0; 380ff462551SAnssi Hannula 381ff462551SAnssi Hannula fail2: input_ff_destroy(dev); 382ff462551SAnssi Hannula fail1: uinput_destroy_device(udev); 383ff462551SAnssi Hannula return error; 3841da177e4SLinus Torvalds } 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds static int uinput_open(struct inode *inode, struct file *file) 3871da177e4SLinus Torvalds { 3881da177e4SLinus Torvalds struct uinput_device *newdev; 3891da177e4SLinus Torvalds 39029506415SDmitry Torokhov newdev = kzalloc(sizeof(struct uinput_device), GFP_KERNEL); 3911da177e4SLinus Torvalds if (!newdev) 39229506415SDmitry Torokhov return -ENOMEM; 39329506415SDmitry Torokhov 394221979aaSDmitry Torokhov mutex_init(&newdev->mutex); 3950048e603SDmitry Torokhov spin_lock_init(&newdev->requests_lock); 3961da177e4SLinus Torvalds init_waitqueue_head(&newdev->requests_waitq); 39729506415SDmitry Torokhov init_waitqueue_head(&newdev->waitq); 39829506415SDmitry Torokhov newdev->state = UIST_NEW_DEVICE; 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds file->private_data = newdev; 401c5bf68feSKirill Smelkov stream_open(inode, file); 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds return 0; 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds 406fbae10dbSDavid Herrmann static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code, 407fbae10dbSDavid Herrmann const struct input_absinfo *abs) 408fbae10dbSDavid Herrmann { 409d77651a2SDmitry Torokhov int min, max, range; 410fbae10dbSDavid Herrmann 411fbae10dbSDavid Herrmann min = abs->minimum; 412fbae10dbSDavid Herrmann max = abs->maximum; 413fbae10dbSDavid Herrmann 4144fef1250SPeter Hutterer if ((min != 0 || max != 0) && max < min) { 415fbae10dbSDavid Herrmann printk(KERN_DEBUG 416fbae10dbSDavid Herrmann "%s: invalid abs[%02x] min:%d max:%d\n", 417fbae10dbSDavid Herrmann UINPUT_NAME, code, min, max); 418fbae10dbSDavid Herrmann return -EINVAL; 419fbae10dbSDavid Herrmann } 420fbae10dbSDavid Herrmann 421d77651a2SDmitry Torokhov if (!check_sub_overflow(max, min, &range) && abs->flat > range) { 422fbae10dbSDavid Herrmann printk(KERN_DEBUG 423fbae10dbSDavid Herrmann "%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n", 424fbae10dbSDavid Herrmann UINPUT_NAME, code, abs->flat, min, max); 425fbae10dbSDavid Herrmann return -EINVAL; 426fbae10dbSDavid Herrmann } 427fbae10dbSDavid Herrmann 428fbae10dbSDavid Herrmann return 0; 429fbae10dbSDavid Herrmann } 430fbae10dbSDavid Herrmann 4311da177e4SLinus Torvalds static int uinput_validate_absbits(struct input_dev *dev) 4321da177e4SLinus Torvalds { 4331da177e4SLinus Torvalds unsigned int cnt; 434fbae10dbSDavid Herrmann int error; 435bcb898e5SDavid Herrmann 436bcb898e5SDavid Herrmann if (!test_bit(EV_ABS, dev->evbit)) 437bcb898e5SDavid Herrmann return 0; 438bcb898e5SDavid Herrmann 439bcb898e5SDavid Herrmann /* 440bcb898e5SDavid Herrmann * Check if absmin/absmax/absfuzz/absflat are sane. 441bcb898e5SDavid Herrmann */ 4421da177e4SLinus Torvalds 443b6d30968SAnshul Garg for_each_set_bit(cnt, dev->absbit, ABS_CNT) { 444fbae10dbSDavid Herrmann if (!dev->absinfo) 445bcb898e5SDavid Herrmann return -EINVAL; 4461da177e4SLinus Torvalds 447fbae10dbSDavid Herrmann error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]); 448fbae10dbSDavid Herrmann if (error) 449fbae10dbSDavid Herrmann return error; 450bcb898e5SDavid Herrmann } 451bcb898e5SDavid Herrmann 452bcb898e5SDavid Herrmann return 0; 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds 455052876f8SBenjamin Tissoires static int uinput_dev_setup(struct uinput_device *udev, 456052876f8SBenjamin Tissoires struct uinput_setup __user *arg) 457052876f8SBenjamin Tissoires { 458052876f8SBenjamin Tissoires struct uinput_setup setup; 459052876f8SBenjamin Tissoires struct input_dev *dev; 460052876f8SBenjamin Tissoires 461052876f8SBenjamin Tissoires if (udev->state == UIST_CREATED) 462052876f8SBenjamin Tissoires return -EINVAL; 463052876f8SBenjamin Tissoires 464052876f8SBenjamin Tissoires if (copy_from_user(&setup, arg, sizeof(setup))) 465052876f8SBenjamin Tissoires return -EFAULT; 466052876f8SBenjamin Tissoires 467052876f8SBenjamin Tissoires if (!setup.name[0]) 468052876f8SBenjamin Tissoires return -EINVAL; 469052876f8SBenjamin Tissoires 470052876f8SBenjamin Tissoires dev = udev->dev; 471052876f8SBenjamin Tissoires dev->id = setup.id; 472052876f8SBenjamin Tissoires udev->ff_effects_max = setup.ff_effects_max; 473052876f8SBenjamin Tissoires 474052876f8SBenjamin Tissoires kfree(dev->name); 475052876f8SBenjamin Tissoires dev->name = kstrndup(setup.name, UINPUT_MAX_NAME_SIZE, GFP_KERNEL); 476052876f8SBenjamin Tissoires if (!dev->name) 477052876f8SBenjamin Tissoires return -ENOMEM; 478052876f8SBenjamin Tissoires 479052876f8SBenjamin Tissoires udev->state = UIST_SETUP_COMPLETE; 480052876f8SBenjamin Tissoires return 0; 481052876f8SBenjamin Tissoires } 482052876f8SBenjamin Tissoires 483052876f8SBenjamin Tissoires static int uinput_abs_setup(struct uinput_device *udev, 484052876f8SBenjamin Tissoires struct uinput_setup __user *arg, size_t size) 485052876f8SBenjamin Tissoires { 486052876f8SBenjamin Tissoires struct uinput_abs_setup setup = {}; 487052876f8SBenjamin Tissoires struct input_dev *dev; 488fbae10dbSDavid Herrmann int error; 489052876f8SBenjamin Tissoires 490052876f8SBenjamin Tissoires if (size > sizeof(setup)) 491052876f8SBenjamin Tissoires return -E2BIG; 492052876f8SBenjamin Tissoires 493052876f8SBenjamin Tissoires if (udev->state == UIST_CREATED) 494052876f8SBenjamin Tissoires return -EINVAL; 495052876f8SBenjamin Tissoires 496052876f8SBenjamin Tissoires if (copy_from_user(&setup, arg, size)) 497052876f8SBenjamin Tissoires return -EFAULT; 498052876f8SBenjamin Tissoires 499052876f8SBenjamin Tissoires if (setup.code > ABS_MAX) 500052876f8SBenjamin Tissoires return -ERANGE; 501052876f8SBenjamin Tissoires 502052876f8SBenjamin Tissoires dev = udev->dev; 503052876f8SBenjamin Tissoires 504fbae10dbSDavid Herrmann error = uinput_validate_absinfo(dev, setup.code, &setup.absinfo); 505fbae10dbSDavid Herrmann if (error) 506fbae10dbSDavid Herrmann return error; 507fbae10dbSDavid Herrmann 508052876f8SBenjamin Tissoires input_alloc_absinfo(dev); 509052876f8SBenjamin Tissoires if (!dev->absinfo) 510052876f8SBenjamin Tissoires return -ENOMEM; 511052876f8SBenjamin Tissoires 512052876f8SBenjamin Tissoires set_bit(setup.code, dev->absbit); 513052876f8SBenjamin Tissoires dev->absinfo[setup.code] = setup.absinfo; 514052876f8SBenjamin Tissoires return 0; 515052876f8SBenjamin Tissoires } 516052876f8SBenjamin Tissoires 517052876f8SBenjamin Tissoires /* legacy setup via write() */ 518052876f8SBenjamin Tissoires static int uinput_setup_device_legacy(struct uinput_device *udev, 51954ce165eSDmitry Torokhov const char __user *buffer, size_t count) 5201da177e4SLinus Torvalds { 5211da177e4SLinus Torvalds struct uinput_user_dev *user_dev; 5221da177e4SLinus Torvalds struct input_dev *dev; 5235d9d6e91SDavid Herrmann int i; 524152c12f5SDmitry Torokhov int retval; 5251da177e4SLinus Torvalds 52629506415SDmitry Torokhov if (count != sizeof(struct uinput_user_dev)) 52729506415SDmitry Torokhov return -EINVAL; 5281da177e4SLinus Torvalds 52929506415SDmitry Torokhov if (!udev->dev) { 53004ce40a6SDmitry Torokhov udev->dev = input_allocate_device(); 53104ce40a6SDmitry Torokhov if (!udev->dev) 53204ce40a6SDmitry Torokhov return -ENOMEM; 53329506415SDmitry Torokhov } 53429506415SDmitry Torokhov 5351da177e4SLinus Torvalds dev = udev->dev; 5361da177e4SLinus Torvalds 5374dfcc271SDmitry Torokhov user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev)); 538163d2770SDan Carpenter if (IS_ERR(user_dev)) 5394dfcc271SDmitry Torokhov return PTR_ERR(user_dev); 5401da177e4SLinus Torvalds 541ff462551SAnssi Hannula udev->ff_effects_max = user_dev->ff_effects_max; 542ff462551SAnssi Hannula 5435d9d6e91SDavid Herrmann /* Ensure name is filled in */ 5445d9d6e91SDavid Herrmann if (!user_dev->name[0]) { 54529506415SDmitry Torokhov retval = -EINVAL; 54629506415SDmitry Torokhov goto exit; 54729506415SDmitry Torokhov } 54829506415SDmitry Torokhov 54929506415SDmitry Torokhov kfree(dev->name); 5505d9d6e91SDavid Herrmann dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE, 5515d9d6e91SDavid Herrmann GFP_KERNEL); 5525d9d6e91SDavid Herrmann if (!dev->name) { 5531da177e4SLinus Torvalds retval = -ENOMEM; 5541da177e4SLinus Torvalds goto exit; 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds dev->id.bustype = user_dev->id.bustype; 5581da177e4SLinus Torvalds dev->id.vendor = user_dev->id.vendor; 5591da177e4SLinus Torvalds dev->id.product = user_dev->id.product; 5601da177e4SLinus Torvalds dev->id.version = user_dev->id.version; 5611da177e4SLinus Torvalds 56272d47362SDmitry Torokhov for (i = 0; i < ABS_CNT; i++) { 563987a6c02SDaniel Mack input_abs_set_max(dev, i, user_dev->absmax[i]); 564987a6c02SDaniel Mack input_abs_set_min(dev, i, user_dev->absmin[i]); 565987a6c02SDaniel Mack input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]); 566987a6c02SDaniel Mack input_abs_set_flat(dev, i, user_dev->absflat[i]); 567987a6c02SDaniel Mack } 5681da177e4SLinus Torvalds 56929506415SDmitry Torokhov retval = uinput_validate_absbits(dev); 57029506415SDmitry Torokhov if (retval < 0) 57129506415SDmitry Torokhov goto exit; 57229506415SDmitry Torokhov 57329506415SDmitry Torokhov udev->state = UIST_SETUP_COMPLETE; 57429506415SDmitry Torokhov retval = count; 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds exit: 5771da177e4SLinus Torvalds kfree(user_dev); 5781da177e4SLinus Torvalds return retval; 5791da177e4SLinus Torvalds } 5801da177e4SLinus Torvalds 581cbf05413SRyan Mallon static ssize_t uinput_inject_events(struct uinput_device *udev, 58254ce165eSDmitry Torokhov const char __user *buffer, size_t count) 5831da177e4SLinus Torvalds { 5841da177e4SLinus Torvalds struct input_event ev; 585cbf05413SRyan Mallon size_t bytes = 0; 5861da177e4SLinus Torvalds 587cbf05413SRyan Mallon if (count != 0 && count < input_event_size()) 58829506415SDmitry Torokhov return -EINVAL; 58929506415SDmitry Torokhov 590cbf05413SRyan Mallon while (bytes + input_event_size() <= count) { 591cbf05413SRyan Mallon /* 592cbf05413SRyan Mallon * Note that even if some events were fetched successfully 593cbf05413SRyan Mallon * we are still going to return EFAULT instead of partial 594cbf05413SRyan Mallon * count to let userspace know that it got it's buffers 595cbf05413SRyan Mallon * all wrong. 596cbf05413SRyan Mallon */ 597cbf05413SRyan Mallon if (input_event_from_user(buffer + bytes, &ev)) 5981da177e4SLinus Torvalds return -EFAULT; 5991da177e4SLinus Torvalds 60029506415SDmitry Torokhov input_event(udev->dev, ev.type, ev.code, ev.value); 601cbf05413SRyan Mallon bytes += input_event_size(); 602cecf1070SDmitry Torokhov cond_resched(); 603cbf05413SRyan Mallon } 60429506415SDmitry Torokhov 605cbf05413SRyan Mallon return bytes; 60629506415SDmitry Torokhov } 60729506415SDmitry Torokhov 60854ce165eSDmitry Torokhov static ssize_t uinput_write(struct file *file, const char __user *buffer, 60954ce165eSDmitry Torokhov size_t count, loff_t *ppos) 61029506415SDmitry Torokhov { 61129506415SDmitry Torokhov struct uinput_device *udev = file->private_data; 61229506415SDmitry Torokhov int retval; 61329506415SDmitry Torokhov 61422ae19c6SDmitry Torokhov if (count == 0) 61522ae19c6SDmitry Torokhov return 0; 61622ae19c6SDmitry Torokhov 617221979aaSDmitry Torokhov retval = mutex_lock_interruptible(&udev->mutex); 61829506415SDmitry Torokhov if (retval) 61929506415SDmitry Torokhov return retval; 62029506415SDmitry Torokhov 62129506415SDmitry Torokhov retval = udev->state == UIST_CREATED ? 622cbf05413SRyan Mallon uinput_inject_events(udev, buffer, count) : 623052876f8SBenjamin Tissoires uinput_setup_device_legacy(udev, buffer, count); 62429506415SDmitry Torokhov 625221979aaSDmitry Torokhov mutex_unlock(&udev->mutex); 62629506415SDmitry Torokhov 62729506415SDmitry Torokhov return retval; 6281da177e4SLinus Torvalds } 6291da177e4SLinus Torvalds 630929d1af5SDmitry Torokhov static bool uinput_fetch_next_event(struct uinput_device *udev, 631929d1af5SDmitry Torokhov struct input_event *event) 632929d1af5SDmitry Torokhov { 633929d1af5SDmitry Torokhov bool have_event; 634929d1af5SDmitry Torokhov 635929d1af5SDmitry Torokhov spin_lock_irq(&udev->dev->event_lock); 636929d1af5SDmitry Torokhov 637929d1af5SDmitry Torokhov have_event = udev->head != udev->tail; 638929d1af5SDmitry Torokhov if (have_event) { 639929d1af5SDmitry Torokhov *event = udev->buff[udev->tail]; 640929d1af5SDmitry Torokhov udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; 641929d1af5SDmitry Torokhov } 642929d1af5SDmitry Torokhov 643929d1af5SDmitry Torokhov spin_unlock_irq(&udev->dev->event_lock); 644929d1af5SDmitry Torokhov 645929d1af5SDmitry Torokhov return have_event; 646929d1af5SDmitry Torokhov } 647929d1af5SDmitry Torokhov 64822ae19c6SDmitry Torokhov static ssize_t uinput_events_to_user(struct uinput_device *udev, 64922ae19c6SDmitry Torokhov char __user *buffer, size_t count) 65022ae19c6SDmitry Torokhov { 65122ae19c6SDmitry Torokhov struct input_event event; 65222ae19c6SDmitry Torokhov size_t read = 0; 65322ae19c6SDmitry Torokhov 65422ae19c6SDmitry Torokhov while (read + input_event_size() <= count && 65522ae19c6SDmitry Torokhov uinput_fetch_next_event(udev, &event)) { 65622ae19c6SDmitry Torokhov 65700ce756cSDmitry Torokhov if (input_event_to_user(buffer + read, &event)) 65800ce756cSDmitry Torokhov return -EFAULT; 65922ae19c6SDmitry Torokhov 66022ae19c6SDmitry Torokhov read += input_event_size(); 66122ae19c6SDmitry Torokhov } 66222ae19c6SDmitry Torokhov 66300ce756cSDmitry Torokhov return read; 66422ae19c6SDmitry Torokhov } 66522ae19c6SDmitry Torokhov 66622ae19c6SDmitry Torokhov static ssize_t uinput_read(struct file *file, char __user *buffer, 66722ae19c6SDmitry Torokhov size_t count, loff_t *ppos) 6681da177e4SLinus Torvalds { 6691da177e4SLinus Torvalds struct uinput_device *udev = file->private_data; 67022ae19c6SDmitry Torokhov ssize_t retval; 6711da177e4SLinus Torvalds 672f40033acSDavid Herrmann if (count != 0 && count < input_event_size()) 673f40033acSDavid Herrmann return -EINVAL; 674f40033acSDavid Herrmann 67522ae19c6SDmitry Torokhov do { 676221979aaSDmitry Torokhov retval = mutex_lock_interruptible(&udev->mutex); 67729506415SDmitry Torokhov if (retval) 67829506415SDmitry Torokhov return retval; 6791da177e4SLinus Torvalds 68022ae19c6SDmitry Torokhov if (udev->state != UIST_CREATED) 68129506415SDmitry Torokhov retval = -ENODEV; 68222ae19c6SDmitry Torokhov else if (udev->head == udev->tail && 68322ae19c6SDmitry Torokhov (file->f_flags & O_NONBLOCK)) 68422ae19c6SDmitry Torokhov retval = -EAGAIN; 68522ae19c6SDmitry Torokhov else 68622ae19c6SDmitry Torokhov retval = uinput_events_to_user(udev, buffer, count); 68729506415SDmitry Torokhov 688221979aaSDmitry Torokhov mutex_unlock(&udev->mutex); 68929506415SDmitry Torokhov 69022ae19c6SDmitry Torokhov if (retval || count == 0) 69122ae19c6SDmitry Torokhov break; 69222ae19c6SDmitry Torokhov 69322ae19c6SDmitry Torokhov if (!(file->f_flags & O_NONBLOCK)) 69422ae19c6SDmitry Torokhov retval = wait_event_interruptible(udev->waitq, 69522ae19c6SDmitry Torokhov udev->head != udev->tail || 69622ae19c6SDmitry Torokhov udev->state != UIST_CREATED); 69722ae19c6SDmitry Torokhov } while (retval == 0); 69822ae19c6SDmitry Torokhov 6991da177e4SLinus Torvalds return retval; 7001da177e4SLinus Torvalds } 7011da177e4SLinus Torvalds 702afc9a42bSAl Viro static __poll_t uinput_poll(struct file *file, poll_table *wait) 7031da177e4SLinus Torvalds { 7041da177e4SLinus Torvalds struct uinput_device *udev = file->private_data; 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds poll_wait(file, &udev->waitq, wait); 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds if (udev->head != udev->tail) 709a9a08845SLinus Torvalds return EPOLLIN | EPOLLRDNORM; 7101da177e4SLinus Torvalds 7111da177e4SLinus Torvalds return 0; 7121da177e4SLinus Torvalds } 7131da177e4SLinus Torvalds 71429506415SDmitry Torokhov static int uinput_release(struct inode *inode, struct file *file) 7151da177e4SLinus Torvalds { 71629506415SDmitry Torokhov struct uinput_device *udev = file->private_data; 7171da177e4SLinus Torvalds 71829506415SDmitry Torokhov uinput_destroy_device(udev); 7191da177e4SLinus Torvalds kfree(udev); 7201da177e4SLinus Torvalds 7211da177e4SLinus Torvalds return 0; 7221da177e4SLinus Torvalds } 7231da177e4SLinus Torvalds 7242d56f3a3SPhilip Langdale #ifdef CONFIG_COMPAT 7252d56f3a3SPhilip Langdale struct uinput_ff_upload_compat { 726c5b3533aSDmitry Torokhov __u32 request_id; 727c5b3533aSDmitry Torokhov __s32 retval; 7282d56f3a3SPhilip Langdale struct ff_effect_compat effect; 7292d56f3a3SPhilip Langdale struct ff_effect_compat old; 7302d56f3a3SPhilip Langdale }; 7312d56f3a3SPhilip Langdale 7322d56f3a3SPhilip Langdale static int uinput_ff_upload_to_user(char __user *buffer, 7332d56f3a3SPhilip Langdale const struct uinput_ff_upload *ff_up) 7342d56f3a3SPhilip Langdale { 735b8b4ead1SAndrew Morton if (in_compat_syscall()) { 7362d56f3a3SPhilip Langdale struct uinput_ff_upload_compat ff_up_compat; 7372d56f3a3SPhilip Langdale 7382d56f3a3SPhilip Langdale ff_up_compat.request_id = ff_up->request_id; 7392d56f3a3SPhilip Langdale ff_up_compat.retval = ff_up->retval; 7402d56f3a3SPhilip Langdale /* 7412d56f3a3SPhilip Langdale * It so happens that the pointer that gives us the trouble 7422d56f3a3SPhilip Langdale * is the last field in the structure. Since we don't support 7432d56f3a3SPhilip Langdale * custom waveforms in uinput anyway we can just copy the whole 7442d56f3a3SPhilip Langdale * thing (to the compat size) and ignore the pointer. 7452d56f3a3SPhilip Langdale */ 7462d56f3a3SPhilip Langdale memcpy(&ff_up_compat.effect, &ff_up->effect, 7472d56f3a3SPhilip Langdale sizeof(struct ff_effect_compat)); 7482d56f3a3SPhilip Langdale memcpy(&ff_up_compat.old, &ff_up->old, 7492d56f3a3SPhilip Langdale sizeof(struct ff_effect_compat)); 7502d56f3a3SPhilip Langdale 7512d56f3a3SPhilip Langdale if (copy_to_user(buffer, &ff_up_compat, 7522d56f3a3SPhilip Langdale sizeof(struct uinput_ff_upload_compat))) 7532d56f3a3SPhilip Langdale return -EFAULT; 7542d56f3a3SPhilip Langdale } else { 7552d56f3a3SPhilip Langdale if (copy_to_user(buffer, ff_up, 7562d56f3a3SPhilip Langdale sizeof(struct uinput_ff_upload))) 7572d56f3a3SPhilip Langdale return -EFAULT; 7582d56f3a3SPhilip Langdale } 7592d56f3a3SPhilip Langdale 7602d56f3a3SPhilip Langdale return 0; 7612d56f3a3SPhilip Langdale } 7622d56f3a3SPhilip Langdale 7632d56f3a3SPhilip Langdale static int uinput_ff_upload_from_user(const char __user *buffer, 7642d56f3a3SPhilip Langdale struct uinput_ff_upload *ff_up) 7652d56f3a3SPhilip Langdale { 766b8b4ead1SAndrew Morton if (in_compat_syscall()) { 7672d56f3a3SPhilip Langdale struct uinput_ff_upload_compat ff_up_compat; 7682d56f3a3SPhilip Langdale 7692d56f3a3SPhilip Langdale if (copy_from_user(&ff_up_compat, buffer, 7702d56f3a3SPhilip Langdale sizeof(struct uinput_ff_upload_compat))) 7712d56f3a3SPhilip Langdale return -EFAULT; 7722d56f3a3SPhilip Langdale 7732d56f3a3SPhilip Langdale ff_up->request_id = ff_up_compat.request_id; 7742d56f3a3SPhilip Langdale ff_up->retval = ff_up_compat.retval; 7752d56f3a3SPhilip Langdale memcpy(&ff_up->effect, &ff_up_compat.effect, 7762d56f3a3SPhilip Langdale sizeof(struct ff_effect_compat)); 7772d56f3a3SPhilip Langdale memcpy(&ff_up->old, &ff_up_compat.old, 7782d56f3a3SPhilip Langdale sizeof(struct ff_effect_compat)); 7792d56f3a3SPhilip Langdale 7802d56f3a3SPhilip Langdale } else { 7812d56f3a3SPhilip Langdale if (copy_from_user(ff_up, buffer, 7822d56f3a3SPhilip Langdale sizeof(struct uinput_ff_upload))) 7832d56f3a3SPhilip Langdale return -EFAULT; 7842d56f3a3SPhilip Langdale } 7852d56f3a3SPhilip Langdale 7862d56f3a3SPhilip Langdale return 0; 7872d56f3a3SPhilip Langdale } 7882d56f3a3SPhilip Langdale 7892d56f3a3SPhilip Langdale #else 7902d56f3a3SPhilip Langdale 7912d56f3a3SPhilip Langdale static int uinput_ff_upload_to_user(char __user *buffer, 7922d56f3a3SPhilip Langdale const struct uinput_ff_upload *ff_up) 7932d56f3a3SPhilip Langdale { 7942d56f3a3SPhilip Langdale if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload))) 7952d56f3a3SPhilip Langdale return -EFAULT; 7962d56f3a3SPhilip Langdale 7972d56f3a3SPhilip Langdale return 0; 7982d56f3a3SPhilip Langdale } 7992d56f3a3SPhilip Langdale 8002d56f3a3SPhilip Langdale static int uinput_ff_upload_from_user(const char __user *buffer, 8012d56f3a3SPhilip Langdale struct uinput_ff_upload *ff_up) 8022d56f3a3SPhilip Langdale { 8032d56f3a3SPhilip Langdale if (copy_from_user(ff_up, buffer, sizeof(struct uinput_ff_upload))) 8042d56f3a3SPhilip Langdale return -EFAULT; 8052d56f3a3SPhilip Langdale 8062d56f3a3SPhilip Langdale return 0; 8072d56f3a3SPhilip Langdale } 8082d56f3a3SPhilip Langdale 8092d56f3a3SPhilip Langdale #endif 8102d56f3a3SPhilip Langdale 81129506415SDmitry Torokhov #define uinput_set_bit(_arg, _bit, _max) \ 81229506415SDmitry Torokhov ({ \ 81329506415SDmitry Torokhov int __ret = 0; \ 81429506415SDmitry Torokhov if (udev->state == UIST_CREATED) \ 81529506415SDmitry Torokhov __ret = -EINVAL; \ 81629506415SDmitry Torokhov else if ((_arg) > (_max)) \ 81729506415SDmitry Torokhov __ret = -EINVAL; \ 81829506415SDmitry Torokhov else set_bit((_arg), udev->dev->_bit); \ 81929506415SDmitry Torokhov __ret; \ 82029506415SDmitry Torokhov }) 8211da177e4SLinus Torvalds 822e3480a61SBenjamin Tissoires static int uinput_str_to_user(void __user *dest, const char *str, 823e3480a61SBenjamin Tissoires unsigned int maxlen) 824e3480a61SBenjamin Tissoires { 825e3480a61SBenjamin Tissoires char __user *p = dest; 826e3480a61SBenjamin Tissoires int len, ret; 827e3480a61SBenjamin Tissoires 828e3480a61SBenjamin Tissoires if (!str) 829e3480a61SBenjamin Tissoires return -ENOENT; 830e3480a61SBenjamin Tissoires 831e3480a61SBenjamin Tissoires if (maxlen == 0) 832e3480a61SBenjamin Tissoires return -EINVAL; 833e3480a61SBenjamin Tissoires 834e3480a61SBenjamin Tissoires len = strlen(str) + 1; 835e3480a61SBenjamin Tissoires if (len > maxlen) 836e3480a61SBenjamin Tissoires len = maxlen; 837e3480a61SBenjamin Tissoires 838e3480a61SBenjamin Tissoires ret = copy_to_user(p, str, len); 839e3480a61SBenjamin Tissoires if (ret) 840e3480a61SBenjamin Tissoires return -EFAULT; 841e3480a61SBenjamin Tissoires 842e3480a61SBenjamin Tissoires /* force terminating '\0' */ 843e3480a61SBenjamin Tissoires ret = put_user(0, p + len - 1); 844e3480a61SBenjamin Tissoires return ret ? -EFAULT : len; 845e3480a61SBenjamin Tissoires } 846e3480a61SBenjamin Tissoires 8472d56f3a3SPhilip Langdale static long uinput_ioctl_handler(struct file *file, unsigned int cmd, 8482d56f3a3SPhilip Langdale unsigned long arg, void __user *p) 8491da177e4SLinus Torvalds { 85029506415SDmitry Torokhov int retval; 8512d56f3a3SPhilip Langdale struct uinput_device *udev = file->private_data; 8521da177e4SLinus Torvalds struct uinput_ff_upload ff_up; 8531da177e4SLinus Torvalds struct uinput_ff_erase ff_erase; 8541da177e4SLinus Torvalds struct uinput_request *req; 8555b6271bdSDmitry Torokhov char *phys; 856e3480a61SBenjamin Tissoires const char *name; 857e3480a61SBenjamin Tissoires unsigned int size; 8581da177e4SLinus Torvalds 859221979aaSDmitry Torokhov retval = mutex_lock_interruptible(&udev->mutex); 86029506415SDmitry Torokhov if (retval) 86129506415SDmitry Torokhov return retval; 86229506415SDmitry Torokhov 86329506415SDmitry Torokhov if (!udev->dev) { 86404ce40a6SDmitry Torokhov udev->dev = input_allocate_device(); 865781f2dd0SDan Carpenter if (!udev->dev) { 866781f2dd0SDan Carpenter retval = -ENOMEM; 867781f2dd0SDan Carpenter goto out; 868781f2dd0SDan Carpenter } 8691da177e4SLinus Torvalds } 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds switch (cmd) { 872ba4e9a61SDavid Herrmann case UI_GET_VERSION: 873c0661652SDmitry Torokhov if (put_user(UINPUT_VERSION, (unsigned int __user *)p)) 874ba4e9a61SDavid Herrmann retval = -EFAULT; 875ba4e9a61SDavid Herrmann goto out; 876ba4e9a61SDavid Herrmann 8771da177e4SLinus Torvalds case UI_DEV_CREATE: 8781da177e4SLinus Torvalds retval = uinput_create_device(udev); 8799d51e801SBenjamin Tisssoires goto out; 8801da177e4SLinus Torvalds 8811da177e4SLinus Torvalds case UI_DEV_DESTROY: 88229506415SDmitry Torokhov uinput_destroy_device(udev); 8839d51e801SBenjamin Tisssoires goto out; 8841da177e4SLinus Torvalds 885052876f8SBenjamin Tissoires case UI_DEV_SETUP: 886052876f8SBenjamin Tissoires retval = uinput_dev_setup(udev, p); 887052876f8SBenjamin Tissoires goto out; 888052876f8SBenjamin Tissoires 889052876f8SBenjamin Tissoires /* UI_ABS_SETUP is handled in the variable size ioctls */ 890052876f8SBenjamin Tissoires 8911da177e4SLinus Torvalds case UI_SET_EVBIT: 89229506415SDmitry Torokhov retval = uinput_set_bit(arg, evbit, EV_MAX); 8939d51e801SBenjamin Tisssoires goto out; 8941da177e4SLinus Torvalds 8951da177e4SLinus Torvalds case UI_SET_KEYBIT: 89629506415SDmitry Torokhov retval = uinput_set_bit(arg, keybit, KEY_MAX); 8979d51e801SBenjamin Tisssoires goto out; 8981da177e4SLinus Torvalds 8991da177e4SLinus Torvalds case UI_SET_RELBIT: 90029506415SDmitry Torokhov retval = uinput_set_bit(arg, relbit, REL_MAX); 9019d51e801SBenjamin Tisssoires goto out; 9021da177e4SLinus Torvalds 9031da177e4SLinus Torvalds case UI_SET_ABSBIT: 90429506415SDmitry Torokhov retval = uinput_set_bit(arg, absbit, ABS_MAX); 9059d51e801SBenjamin Tisssoires goto out; 9061da177e4SLinus Torvalds 9071da177e4SLinus Torvalds case UI_SET_MSCBIT: 90829506415SDmitry Torokhov retval = uinput_set_bit(arg, mscbit, MSC_MAX); 9099d51e801SBenjamin Tisssoires goto out; 9101da177e4SLinus Torvalds 9111da177e4SLinus Torvalds case UI_SET_LEDBIT: 91229506415SDmitry Torokhov retval = uinput_set_bit(arg, ledbit, LED_MAX); 9139d51e801SBenjamin Tisssoires goto out; 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds case UI_SET_SNDBIT: 91629506415SDmitry Torokhov retval = uinput_set_bit(arg, sndbit, SND_MAX); 9179d51e801SBenjamin Tisssoires goto out; 9181da177e4SLinus Torvalds 9191da177e4SLinus Torvalds case UI_SET_FFBIT: 92029506415SDmitry Torokhov retval = uinput_set_bit(arg, ffbit, FF_MAX); 9219d51e801SBenjamin Tisssoires goto out; 9221da177e4SLinus Torvalds 92359c7c037SDmitry Torokhov case UI_SET_SWBIT: 92459c7c037SDmitry Torokhov retval = uinput_set_bit(arg, swbit, SW_MAX); 9259d51e801SBenjamin Tisssoires goto out; 92659c7c037SDmitry Torokhov 92785b77200SHenrik Rydberg case UI_SET_PROPBIT: 92885b77200SHenrik Rydberg retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX); 9299d51e801SBenjamin Tisssoires goto out; 93085b77200SHenrik Rydberg 9311da177e4SLinus Torvalds case UI_SET_PHYS: 93229506415SDmitry Torokhov if (udev->state == UIST_CREATED) { 93329506415SDmitry Torokhov retval = -EINVAL; 93429506415SDmitry Torokhov goto out; 93529506415SDmitry Torokhov } 9364dfcc271SDmitry Torokhov 9374dfcc271SDmitry Torokhov phys = strndup_user(p, 1024); 9384dfcc271SDmitry Torokhov if (IS_ERR(phys)) { 9394dfcc271SDmitry Torokhov retval = PTR_ERR(phys); 9404dfcc271SDmitry Torokhov goto out; 9411da177e4SLinus Torvalds } 9424dfcc271SDmitry Torokhov 9431da177e4SLinus Torvalds kfree(udev->dev->phys); 9444dfcc271SDmitry Torokhov udev->dev->phys = phys; 9459d51e801SBenjamin Tisssoires goto out; 9461da177e4SLinus Torvalds 9471da177e4SLinus Torvalds case UI_BEGIN_FF_UPLOAD: 9482d56f3a3SPhilip Langdale retval = uinput_ff_upload_from_user(p, &ff_up); 9492d56f3a3SPhilip Langdale if (retval) 9509d51e801SBenjamin Tisssoires goto out; 9512d56f3a3SPhilip Langdale 9521da177e4SLinus Torvalds req = uinput_request_find(udev, ff_up.request_id); 95354ce165eSDmitry Torokhov if (!req || req->code != UI_FF_UPLOAD || 95454ce165eSDmitry Torokhov !req->u.upload.effect) { 9551da177e4SLinus Torvalds retval = -EINVAL; 9569d51e801SBenjamin Tisssoires goto out; 9571da177e4SLinus Torvalds } 9582d56f3a3SPhilip Langdale 9591da177e4SLinus Torvalds ff_up.retval = 0; 9602d56f3a3SPhilip Langdale ff_up.effect = *req->u.upload.effect; 961ff462551SAnssi Hannula if (req->u.upload.old) 9622d56f3a3SPhilip Langdale ff_up.old = *req->u.upload.old; 963ff462551SAnssi Hannula else 964ff462551SAnssi Hannula memset(&ff_up.old, 0, sizeof(struct ff_effect)); 965ff462551SAnssi Hannula 9662d56f3a3SPhilip Langdale retval = uinput_ff_upload_to_user(p, &ff_up); 9679d51e801SBenjamin Tisssoires goto out; 9681da177e4SLinus Torvalds 9691da177e4SLinus Torvalds case UI_BEGIN_FF_ERASE: 9701da177e4SLinus Torvalds if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { 9711da177e4SLinus Torvalds retval = -EFAULT; 9729d51e801SBenjamin Tisssoires goto out; 9731da177e4SLinus Torvalds } 9742d56f3a3SPhilip Langdale 9751da177e4SLinus Torvalds req = uinput_request_find(udev, ff_erase.request_id); 9762d56f3a3SPhilip Langdale if (!req || req->code != UI_FF_ERASE) { 9771da177e4SLinus Torvalds retval = -EINVAL; 9789d51e801SBenjamin Tisssoires goto out; 9791da177e4SLinus Torvalds } 9802d56f3a3SPhilip Langdale 9811da177e4SLinus Torvalds ff_erase.retval = 0; 9821da177e4SLinus Torvalds ff_erase.effect_id = req->u.effect_id; 9831da177e4SLinus Torvalds if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) { 9841da177e4SLinus Torvalds retval = -EFAULT; 9859d51e801SBenjamin Tisssoires goto out; 9861da177e4SLinus Torvalds } 9872d56f3a3SPhilip Langdale 9889d51e801SBenjamin Tisssoires goto out; 9891da177e4SLinus Torvalds 9901da177e4SLinus Torvalds case UI_END_FF_UPLOAD: 9912d56f3a3SPhilip Langdale retval = uinput_ff_upload_from_user(p, &ff_up); 9922d56f3a3SPhilip Langdale if (retval) 9939d51e801SBenjamin Tisssoires goto out; 9942d56f3a3SPhilip Langdale 9951da177e4SLinus Torvalds req = uinput_request_find(udev, ff_up.request_id); 9962d56f3a3SPhilip Langdale if (!req || req->code != UI_FF_UPLOAD || 9972d56f3a3SPhilip Langdale !req->u.upload.effect) { 9981da177e4SLinus Torvalds retval = -EINVAL; 9999d51e801SBenjamin Tisssoires goto out; 10001da177e4SLinus Torvalds } 10012d56f3a3SPhilip Langdale 10021da177e4SLinus Torvalds req->retval = ff_up.retval; 10036b4877c7SDmitry Torokhov complete(&req->done); 10049d51e801SBenjamin Tisssoires goto out; 10051da177e4SLinus Torvalds 10061da177e4SLinus Torvalds case UI_END_FF_ERASE: 10071da177e4SLinus Torvalds if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { 10081da177e4SLinus Torvalds retval = -EFAULT; 10099d51e801SBenjamin Tisssoires goto out; 10101da177e4SLinus Torvalds } 10112d56f3a3SPhilip Langdale 10121da177e4SLinus Torvalds req = uinput_request_find(udev, ff_erase.request_id); 10132d56f3a3SPhilip Langdale if (!req || req->code != UI_FF_ERASE) { 10141da177e4SLinus Torvalds retval = -EINVAL; 10159d51e801SBenjamin Tisssoires goto out; 10161da177e4SLinus Torvalds } 10172d56f3a3SPhilip Langdale 10181da177e4SLinus Torvalds req->retval = ff_erase.retval; 10196b4877c7SDmitry Torokhov complete(&req->done); 10209d51e801SBenjamin Tisssoires goto out; 10211da177e4SLinus Torvalds } 102229506415SDmitry Torokhov 1023e3480a61SBenjamin Tissoires size = _IOC_SIZE(cmd); 1024e3480a61SBenjamin Tissoires 1025e3480a61SBenjamin Tissoires /* Now check variable-length commands */ 1026e3480a61SBenjamin Tissoires switch (cmd & ~IOCSIZE_MASK) { 1027e3480a61SBenjamin Tissoires case UI_GET_SYSNAME(0): 1028e3480a61SBenjamin Tissoires if (udev->state != UIST_CREATED) { 1029e3480a61SBenjamin Tissoires retval = -ENOENT; 1030e3480a61SBenjamin Tissoires goto out; 1031e3480a61SBenjamin Tissoires } 1032e3480a61SBenjamin Tissoires name = dev_name(&udev->dev->dev); 1033e3480a61SBenjamin Tissoires retval = uinput_str_to_user(p, name, size); 1034e3480a61SBenjamin Tissoires goto out; 1035052876f8SBenjamin Tissoires 1036052876f8SBenjamin Tissoires case UI_ABS_SETUP & ~IOCSIZE_MASK: 1037052876f8SBenjamin Tissoires retval = uinput_abs_setup(udev, p, size); 1038052876f8SBenjamin Tissoires goto out; 1039e3480a61SBenjamin Tissoires } 1040e3480a61SBenjamin Tissoires 10419d51e801SBenjamin Tisssoires retval = -EINVAL; 104229506415SDmitry Torokhov out: 1043221979aaSDmitry Torokhov mutex_unlock(&udev->mutex); 10441da177e4SLinus Torvalds return retval; 10451da177e4SLinus Torvalds } 10461da177e4SLinus Torvalds 10472d56f3a3SPhilip Langdale static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 10482d56f3a3SPhilip Langdale { 10492d56f3a3SPhilip Langdale return uinput_ioctl_handler(file, cmd, arg, (void __user *)arg); 10502d56f3a3SPhilip Langdale } 10512d56f3a3SPhilip Langdale 10522d56f3a3SPhilip Langdale #ifdef CONFIG_COMPAT 1053affa80bdSRicky Liang 1054affa80bdSRicky Liang #define UI_SET_PHYS_COMPAT _IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t) 1055affa80bdSRicky Liang 105654ce165eSDmitry Torokhov static long uinput_compat_ioctl(struct file *file, 105754ce165eSDmitry Torokhov unsigned int cmd, unsigned long arg) 10582d56f3a3SPhilip Langdale { 1059affa80bdSRicky Liang if (cmd == UI_SET_PHYS_COMPAT) 1060affa80bdSRicky Liang cmd = UI_SET_PHYS; 1061affa80bdSRicky Liang 10622d56f3a3SPhilip Langdale return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg)); 10632d56f3a3SPhilip Langdale } 10642d56f3a3SPhilip Langdale #endif 10652d56f3a3SPhilip Langdale 10662b8693c0SArjan van de Ven static const struct file_operations uinput_fops = { 10671da177e4SLinus Torvalds .owner = THIS_MODULE, 10681da177e4SLinus Torvalds .open = uinput_open, 106929506415SDmitry Torokhov .release = uinput_release, 10701da177e4SLinus Torvalds .read = uinput_read, 10711da177e4SLinus Torvalds .write = uinput_write, 10721da177e4SLinus Torvalds .poll = uinput_poll, 107329506415SDmitry Torokhov .unlocked_ioctl = uinput_ioctl, 10742d56f3a3SPhilip Langdale #ifdef CONFIG_COMPAT 10752d56f3a3SPhilip Langdale .compat_ioctl = uinput_compat_ioctl, 10762d56f3a3SPhilip Langdale #endif 10776038f373SArnd Bergmann .llseek = no_llseek, 10781da177e4SLinus Torvalds }; 10791da177e4SLinus Torvalds 10801da177e4SLinus Torvalds static struct miscdevice uinput_misc = { 10811da177e4SLinus Torvalds .fops = &uinput_fops, 10821da177e4SLinus Torvalds .minor = UINPUT_MINOR, 10831da177e4SLinus Torvalds .name = UINPUT_NAME, 10841da177e4SLinus Torvalds }; 1085ca75d601SPrasannaKumar Muralidharan module_misc_device(uinput_misc); 1086ca75d601SPrasannaKumar Muralidharan 10878905aaafSKay Sievers MODULE_ALIAS_MISCDEV(UINPUT_MINOR); 10888905aaafSKay Sievers MODULE_ALIAS("devname:" UINPUT_NAME); 10891da177e4SLinus Torvalds 10901da177e4SLinus Torvalds MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); 10911da177e4SLinus Torvalds MODULE_DESCRIPTION("User level driver support for input subsystem"); 10921da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 1093