18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Event char devices, giving access to raw input device events. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 1999-2002 Vojtech Pavlik 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define EVDEV_MINOR_BASE 64 118c2ecf20Sopenharmony_ci#define EVDEV_MINORS 32 128c2ecf20Sopenharmony_ci#define EVDEV_MIN_BUFFER_SIZE 64U 138c2ecf20Sopenharmony_ci#define EVDEV_BUF_PACKETS 8 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/poll.h> 168c2ecf20Sopenharmony_ci#include <linux/sched.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 198c2ecf20Sopenharmony_ci#include <linux/mm.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/init.h> 228c2ecf20Sopenharmony_ci#include <linux/input/mt.h> 238c2ecf20Sopenharmony_ci#include <linux/major.h> 248c2ecf20Sopenharmony_ci#include <linux/device.h> 258c2ecf20Sopenharmony_ci#include <linux/cdev.h> 268c2ecf20Sopenharmony_ci#include "input-compat.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct evdev { 298c2ecf20Sopenharmony_ci int open; 308c2ecf20Sopenharmony_ci struct input_handle handle; 318c2ecf20Sopenharmony_ci struct evdev_client __rcu *grab; 328c2ecf20Sopenharmony_ci struct list_head client_list; 338c2ecf20Sopenharmony_ci spinlock_t client_lock; /* protects client_list */ 348c2ecf20Sopenharmony_ci struct mutex mutex; 358c2ecf20Sopenharmony_ci struct device dev; 368c2ecf20Sopenharmony_ci struct cdev cdev; 378c2ecf20Sopenharmony_ci bool exist; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct evdev_client { 418c2ecf20Sopenharmony_ci unsigned int head; 428c2ecf20Sopenharmony_ci unsigned int tail; 438c2ecf20Sopenharmony_ci unsigned int packet_head; /* [future] position of the first element of next packet */ 448c2ecf20Sopenharmony_ci spinlock_t buffer_lock; /* protects access to buffer, head and tail */ 458c2ecf20Sopenharmony_ci wait_queue_head_t wait; 468c2ecf20Sopenharmony_ci struct fasync_struct *fasync; 478c2ecf20Sopenharmony_ci struct evdev *evdev; 488c2ecf20Sopenharmony_ci struct list_head node; 498c2ecf20Sopenharmony_ci enum input_clock_type clk_type; 508c2ecf20Sopenharmony_ci bool revoked; 518c2ecf20Sopenharmony_ci unsigned long *evmasks[EV_CNT]; 528c2ecf20Sopenharmony_ci unsigned int bufsize; 538c2ecf20Sopenharmony_ci struct input_event buffer[]; 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic size_t evdev_get_mask_cnt(unsigned int type) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci static const size_t counts[EV_CNT] = { 598c2ecf20Sopenharmony_ci /* EV_SYN==0 is EV_CNT, _not_ SYN_CNT, see EVIOCGBIT */ 608c2ecf20Sopenharmony_ci [EV_SYN] = EV_CNT, 618c2ecf20Sopenharmony_ci [EV_KEY] = KEY_CNT, 628c2ecf20Sopenharmony_ci [EV_REL] = REL_CNT, 638c2ecf20Sopenharmony_ci [EV_ABS] = ABS_CNT, 648c2ecf20Sopenharmony_ci [EV_MSC] = MSC_CNT, 658c2ecf20Sopenharmony_ci [EV_SW] = SW_CNT, 668c2ecf20Sopenharmony_ci [EV_LED] = LED_CNT, 678c2ecf20Sopenharmony_ci [EV_SND] = SND_CNT, 688c2ecf20Sopenharmony_ci [EV_FF] = FF_CNT, 698c2ecf20Sopenharmony_ci }; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return (type < EV_CNT) ? counts[type] : 0; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* requires the buffer lock to be held */ 758c2ecf20Sopenharmony_cistatic bool __evdev_is_filtered(struct evdev_client *client, 768c2ecf20Sopenharmony_ci unsigned int type, 778c2ecf20Sopenharmony_ci unsigned int code) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci unsigned long *mask; 808c2ecf20Sopenharmony_ci size_t cnt; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* EV_SYN and unknown codes are never filtered */ 838c2ecf20Sopenharmony_ci if (type == EV_SYN || type >= EV_CNT) 848c2ecf20Sopenharmony_ci return false; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* first test whether the type is filtered */ 878c2ecf20Sopenharmony_ci mask = client->evmasks[0]; 888c2ecf20Sopenharmony_ci if (mask && !test_bit(type, mask)) 898c2ecf20Sopenharmony_ci return true; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* unknown values are never filtered */ 928c2ecf20Sopenharmony_ci cnt = evdev_get_mask_cnt(type); 938c2ecf20Sopenharmony_ci if (!cnt || code >= cnt) 948c2ecf20Sopenharmony_ci return false; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci mask = client->evmasks[type]; 978c2ecf20Sopenharmony_ci return mask && !test_bit(code, mask); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* flush queued events of type @type, caller must hold client->buffer_lock */ 1018c2ecf20Sopenharmony_cistatic void __evdev_flush_queue(struct evdev_client *client, unsigned int type) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci unsigned int i, head, num; 1048c2ecf20Sopenharmony_ci unsigned int mask = client->bufsize - 1; 1058c2ecf20Sopenharmony_ci bool is_report; 1068c2ecf20Sopenharmony_ci struct input_event *ev; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci BUG_ON(type == EV_SYN); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci head = client->tail; 1118c2ecf20Sopenharmony_ci client->packet_head = client->tail; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* init to 1 so a leading SYN_REPORT will not be dropped */ 1148c2ecf20Sopenharmony_ci num = 1; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci for (i = client->tail; i != client->head; i = (i + 1) & mask) { 1178c2ecf20Sopenharmony_ci ev = &client->buffer[i]; 1188c2ecf20Sopenharmony_ci is_report = ev->type == EV_SYN && ev->code == SYN_REPORT; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (ev->type == type) { 1218c2ecf20Sopenharmony_ci /* drop matched entry */ 1228c2ecf20Sopenharmony_ci continue; 1238c2ecf20Sopenharmony_ci } else if (is_report && !num) { 1248c2ecf20Sopenharmony_ci /* drop empty SYN_REPORT groups */ 1258c2ecf20Sopenharmony_ci continue; 1268c2ecf20Sopenharmony_ci } else if (head != i) { 1278c2ecf20Sopenharmony_ci /* move entry to fill the gap */ 1288c2ecf20Sopenharmony_ci client->buffer[head] = *ev; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci num++; 1328c2ecf20Sopenharmony_ci head = (head + 1) & mask; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (is_report) { 1358c2ecf20Sopenharmony_ci num = 0; 1368c2ecf20Sopenharmony_ci client->packet_head = head; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci client->head = head; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void __evdev_queue_syn_dropped(struct evdev_client *client) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci ktime_t *ev_time = input_get_timestamp(client->evdev->handle.dev); 1468c2ecf20Sopenharmony_ci struct timespec64 ts = ktime_to_timespec64(ev_time[client->clk_type]); 1478c2ecf20Sopenharmony_ci struct input_event ev; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci ev.input_event_sec = ts.tv_sec; 1508c2ecf20Sopenharmony_ci ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC; 1518c2ecf20Sopenharmony_ci ev.type = EV_SYN; 1528c2ecf20Sopenharmony_ci ev.code = SYN_DROPPED; 1538c2ecf20Sopenharmony_ci ev.value = 0; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci client->buffer[client->head++] = ev; 1568c2ecf20Sopenharmony_ci client->head &= client->bufsize - 1; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (unlikely(client->head == client->tail)) { 1598c2ecf20Sopenharmony_ci /* drop queue but keep our SYN_DROPPED event */ 1608c2ecf20Sopenharmony_ci client->tail = (client->head - 1) & (client->bufsize - 1); 1618c2ecf20Sopenharmony_ci client->packet_head = client->tail; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void evdev_queue_syn_dropped(struct evdev_client *client) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci unsigned long flags; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci spin_lock_irqsave(&client->buffer_lock, flags); 1708c2ecf20Sopenharmony_ci __evdev_queue_syn_dropped(client); 1718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&client->buffer_lock, flags); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci unsigned long flags; 1778c2ecf20Sopenharmony_ci enum input_clock_type clk_type; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci switch (clkid) { 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci case CLOCK_REALTIME: 1828c2ecf20Sopenharmony_ci clk_type = INPUT_CLK_REAL; 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci case CLOCK_MONOTONIC: 1858c2ecf20Sopenharmony_ci clk_type = INPUT_CLK_MONO; 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci case CLOCK_BOOTTIME: 1888c2ecf20Sopenharmony_ci clk_type = INPUT_CLK_BOOT; 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci default: 1918c2ecf20Sopenharmony_ci return -EINVAL; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (client->clk_type != clk_type) { 1958c2ecf20Sopenharmony_ci client->clk_type = clk_type; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* 1988c2ecf20Sopenharmony_ci * Flush pending events and queue SYN_DROPPED event, 1998c2ecf20Sopenharmony_ci * but only if the queue is not empty. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci spin_lock_irqsave(&client->buffer_lock, flags); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (client->head != client->tail) { 2048c2ecf20Sopenharmony_ci client->packet_head = client->head = client->tail; 2058c2ecf20Sopenharmony_ci __evdev_queue_syn_dropped(client); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&client->buffer_lock, flags); 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return 0; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic void __pass_event(struct evdev_client *client, 2158c2ecf20Sopenharmony_ci const struct input_event *event) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci client->buffer[client->head++] = *event; 2188c2ecf20Sopenharmony_ci client->head &= client->bufsize - 1; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (unlikely(client->head == client->tail)) { 2218c2ecf20Sopenharmony_ci /* 2228c2ecf20Sopenharmony_ci * This effectively "drops" all unconsumed events, leaving 2238c2ecf20Sopenharmony_ci * EV_SYN/SYN_DROPPED plus the newest event in the queue. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci client->tail = (client->head - 2) & (client->bufsize - 1); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci client->buffer[client->tail] = (struct input_event) { 2288c2ecf20Sopenharmony_ci .input_event_sec = event->input_event_sec, 2298c2ecf20Sopenharmony_ci .input_event_usec = event->input_event_usec, 2308c2ecf20Sopenharmony_ci .type = EV_SYN, 2318c2ecf20Sopenharmony_ci .code = SYN_DROPPED, 2328c2ecf20Sopenharmony_ci .value = 0, 2338c2ecf20Sopenharmony_ci }; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci client->packet_head = client->tail; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (event->type == EV_SYN && event->code == SYN_REPORT) { 2398c2ecf20Sopenharmony_ci client->packet_head = client->head; 2408c2ecf20Sopenharmony_ci kill_fasync(&client->fasync, SIGIO, POLL_IN); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic void evdev_pass_values(struct evdev_client *client, 2458c2ecf20Sopenharmony_ci const struct input_value *vals, unsigned int count, 2468c2ecf20Sopenharmony_ci ktime_t *ev_time) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci const struct input_value *v; 2498c2ecf20Sopenharmony_ci struct input_event event; 2508c2ecf20Sopenharmony_ci struct timespec64 ts; 2518c2ecf20Sopenharmony_ci bool wakeup = false; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (client->revoked) 2548c2ecf20Sopenharmony_ci return; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci ts = ktime_to_timespec64(ev_time[client->clk_type]); 2578c2ecf20Sopenharmony_ci event.input_event_sec = ts.tv_sec; 2588c2ecf20Sopenharmony_ci event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* Interrupts are disabled, just acquire the lock. */ 2618c2ecf20Sopenharmony_ci spin_lock(&client->buffer_lock); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci for (v = vals; v != vals + count; v++) { 2648c2ecf20Sopenharmony_ci if (__evdev_is_filtered(client, v->type, v->code)) 2658c2ecf20Sopenharmony_ci continue; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (v->type == EV_SYN && v->code == SYN_REPORT) { 2688c2ecf20Sopenharmony_ci /* drop empty SYN_REPORT */ 2698c2ecf20Sopenharmony_ci if (client->packet_head == client->head) 2708c2ecf20Sopenharmony_ci continue; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci wakeup = true; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci event.type = v->type; 2768c2ecf20Sopenharmony_ci event.code = v->code; 2778c2ecf20Sopenharmony_ci event.value = v->value; 2788c2ecf20Sopenharmony_ci __pass_event(client, &event); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci spin_unlock(&client->buffer_lock); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (wakeup) 2848c2ecf20Sopenharmony_ci wake_up_interruptible_poll(&client->wait, 2858c2ecf20Sopenharmony_ci EPOLLIN | EPOLLOUT | EPOLLRDNORM | EPOLLWRNORM); 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci/* 2898c2ecf20Sopenharmony_ci * Pass incoming events to all connected clients. 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_cistatic void evdev_events(struct input_handle *handle, 2928c2ecf20Sopenharmony_ci const struct input_value *vals, unsigned int count) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct evdev *evdev = handle->private; 2958c2ecf20Sopenharmony_ci struct evdev_client *client; 2968c2ecf20Sopenharmony_ci ktime_t *ev_time = input_get_timestamp(handle->dev); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci rcu_read_lock(); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci client = rcu_dereference(evdev->grab); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (client) 3038c2ecf20Sopenharmony_ci evdev_pass_values(client, vals, count, ev_time); 3048c2ecf20Sopenharmony_ci else 3058c2ecf20Sopenharmony_ci list_for_each_entry_rcu(client, &evdev->client_list, node) 3068c2ecf20Sopenharmony_ci evdev_pass_values(client, vals, count, ev_time); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci rcu_read_unlock(); 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/* 3128c2ecf20Sopenharmony_ci * Pass incoming event to all connected clients. 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_cistatic void evdev_event(struct input_handle *handle, 3158c2ecf20Sopenharmony_ci unsigned int type, unsigned int code, int value) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct input_value vals[] = { { type, code, value } }; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci evdev_events(handle, vals, 1); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int evdev_fasync(int fd, struct file *file, int on) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct evdev_client *client = file->private_data; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return fasync_helper(fd, file, on, &client->fasync); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic void evdev_free(struct device *dev) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct evdev *evdev = container_of(dev, struct evdev, dev); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci input_put_device(evdev->handle.dev); 3348c2ecf20Sopenharmony_ci kfree(evdev); 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci/* 3388c2ecf20Sopenharmony_ci * Grabs an event device (along with underlying input device). 3398c2ecf20Sopenharmony_ci * This function is called with evdev->mutex taken. 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_cistatic int evdev_grab(struct evdev *evdev, struct evdev_client *client) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci int error; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (evdev->grab) 3468c2ecf20Sopenharmony_ci return -EBUSY; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci error = input_grab_device(&evdev->handle); 3498c2ecf20Sopenharmony_ci if (error) 3508c2ecf20Sopenharmony_ci return error; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci rcu_assign_pointer(evdev->grab, client); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return 0; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic int evdev_ungrab(struct evdev *evdev, struct evdev_client *client) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci struct evdev_client *grab = rcu_dereference_protected(evdev->grab, 3608c2ecf20Sopenharmony_ci lockdep_is_held(&evdev->mutex)); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (grab != client) 3638c2ecf20Sopenharmony_ci return -EINVAL; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci rcu_assign_pointer(evdev->grab, NULL); 3668c2ecf20Sopenharmony_ci synchronize_rcu(); 3678c2ecf20Sopenharmony_ci input_release_device(&evdev->handle); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return 0; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic void evdev_attach_client(struct evdev *evdev, 3738c2ecf20Sopenharmony_ci struct evdev_client *client) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci spin_lock(&evdev->client_lock); 3768c2ecf20Sopenharmony_ci list_add_tail_rcu(&client->node, &evdev->client_list); 3778c2ecf20Sopenharmony_ci spin_unlock(&evdev->client_lock); 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic void evdev_detach_client(struct evdev *evdev, 3818c2ecf20Sopenharmony_ci struct evdev_client *client) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci spin_lock(&evdev->client_lock); 3848c2ecf20Sopenharmony_ci list_del_rcu(&client->node); 3858c2ecf20Sopenharmony_ci spin_unlock(&evdev->client_lock); 3868c2ecf20Sopenharmony_ci synchronize_rcu(); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int evdev_open_device(struct evdev *evdev) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci int retval; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci retval = mutex_lock_interruptible(&evdev->mutex); 3948c2ecf20Sopenharmony_ci if (retval) 3958c2ecf20Sopenharmony_ci return retval; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (!evdev->exist) 3988c2ecf20Sopenharmony_ci retval = -ENODEV; 3998c2ecf20Sopenharmony_ci else if (!evdev->open++) { 4008c2ecf20Sopenharmony_ci retval = input_open_device(&evdev->handle); 4018c2ecf20Sopenharmony_ci if (retval) 4028c2ecf20Sopenharmony_ci evdev->open--; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci mutex_unlock(&evdev->mutex); 4068c2ecf20Sopenharmony_ci return retval; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void evdev_close_device(struct evdev *evdev) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci mutex_lock(&evdev->mutex); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (evdev->exist && !--evdev->open) 4148c2ecf20Sopenharmony_ci input_close_device(&evdev->handle); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci mutex_unlock(&evdev->mutex); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/* 4208c2ecf20Sopenharmony_ci * Wake up users waiting for IO so they can disconnect from 4218c2ecf20Sopenharmony_ci * dead device. 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_cistatic void evdev_hangup(struct evdev *evdev) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct evdev_client *client; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci spin_lock(&evdev->client_lock); 4288c2ecf20Sopenharmony_ci list_for_each_entry(client, &evdev->client_list, node) { 4298c2ecf20Sopenharmony_ci kill_fasync(&client->fasync, SIGIO, POLL_HUP); 4308c2ecf20Sopenharmony_ci wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci spin_unlock(&evdev->client_lock); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int evdev_release(struct inode *inode, struct file *file) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci struct evdev_client *client = file->private_data; 4388c2ecf20Sopenharmony_ci struct evdev *evdev = client->evdev; 4398c2ecf20Sopenharmony_ci unsigned int i; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci mutex_lock(&evdev->mutex); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (evdev->exist && !client->revoked) 4448c2ecf20Sopenharmony_ci input_flush_device(&evdev->handle, file); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci evdev_ungrab(evdev, client); 4478c2ecf20Sopenharmony_ci mutex_unlock(&evdev->mutex); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci evdev_detach_client(evdev, client); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci for (i = 0; i < EV_CNT; ++i) 4528c2ecf20Sopenharmony_ci bitmap_free(client->evmasks[i]); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci kvfree(client); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci evdev_close_device(evdev); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic unsigned int evdev_compute_buffer_size(struct input_dev *dev) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci unsigned int n_events = 4648c2ecf20Sopenharmony_ci max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS, 4658c2ecf20Sopenharmony_ci EVDEV_MIN_BUFFER_SIZE); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return roundup_pow_of_two(n_events); 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic int evdev_open(struct inode *inode, struct file *file) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev); 4738c2ecf20Sopenharmony_ci unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev); 4748c2ecf20Sopenharmony_ci struct evdev_client *client; 4758c2ecf20Sopenharmony_ci int error; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci client = kvzalloc(struct_size(client, buffer, bufsize), GFP_KERNEL); 4788c2ecf20Sopenharmony_ci if (!client) 4798c2ecf20Sopenharmony_ci return -ENOMEM; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci init_waitqueue_head(&client->wait); 4828c2ecf20Sopenharmony_ci client->bufsize = bufsize; 4838c2ecf20Sopenharmony_ci spin_lock_init(&client->buffer_lock); 4848c2ecf20Sopenharmony_ci client->evdev = evdev; 4858c2ecf20Sopenharmony_ci evdev_attach_client(evdev, client); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci error = evdev_open_device(evdev); 4888c2ecf20Sopenharmony_ci if (error) 4898c2ecf20Sopenharmony_ci goto err_free_client; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci file->private_data = client; 4928c2ecf20Sopenharmony_ci stream_open(inode, file); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return 0; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci err_free_client: 4978c2ecf20Sopenharmony_ci evdev_detach_client(evdev, client); 4988c2ecf20Sopenharmony_ci kvfree(client); 4998c2ecf20Sopenharmony_ci return error; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic ssize_t evdev_write(struct file *file, const char __user *buffer, 5038c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci struct evdev_client *client = file->private_data; 5068c2ecf20Sopenharmony_ci struct evdev *evdev = client->evdev; 5078c2ecf20Sopenharmony_ci struct input_event event; 5088c2ecf20Sopenharmony_ci int retval = 0; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (count != 0 && count < input_event_size()) 5118c2ecf20Sopenharmony_ci return -EINVAL; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci retval = mutex_lock_interruptible(&evdev->mutex); 5148c2ecf20Sopenharmony_ci if (retval) 5158c2ecf20Sopenharmony_ci return retval; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (!evdev->exist || client->revoked) { 5188c2ecf20Sopenharmony_ci retval = -ENODEV; 5198c2ecf20Sopenharmony_ci goto out; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci while (retval + input_event_size() <= count) { 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (input_event_from_user(buffer + retval, &event)) { 5258c2ecf20Sopenharmony_ci retval = -EFAULT; 5268c2ecf20Sopenharmony_ci goto out; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci retval += input_event_size(); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci input_inject_event(&evdev->handle, 5318c2ecf20Sopenharmony_ci event.type, event.code, event.value); 5328c2ecf20Sopenharmony_ci cond_resched(); 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci out: 5368c2ecf20Sopenharmony_ci mutex_unlock(&evdev->mutex); 5378c2ecf20Sopenharmony_ci return retval; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic int evdev_fetch_next_event(struct evdev_client *client, 5418c2ecf20Sopenharmony_ci struct input_event *event) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci int have_event; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci spin_lock_irq(&client->buffer_lock); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci have_event = client->packet_head != client->tail; 5488c2ecf20Sopenharmony_ci if (have_event) { 5498c2ecf20Sopenharmony_ci *event = client->buffer[client->tail++]; 5508c2ecf20Sopenharmony_ci client->tail &= client->bufsize - 1; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci spin_unlock_irq(&client->buffer_lock); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci return have_event; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistatic ssize_t evdev_read(struct file *file, char __user *buffer, 5598c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci struct evdev_client *client = file->private_data; 5628c2ecf20Sopenharmony_ci struct evdev *evdev = client->evdev; 5638c2ecf20Sopenharmony_ci struct input_event event; 5648c2ecf20Sopenharmony_ci size_t read = 0; 5658c2ecf20Sopenharmony_ci int error; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (count != 0 && count < input_event_size()) 5688c2ecf20Sopenharmony_ci return -EINVAL; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci for (;;) { 5718c2ecf20Sopenharmony_ci if (!evdev->exist || client->revoked) 5728c2ecf20Sopenharmony_ci return -ENODEV; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (client->packet_head == client->tail && 5758c2ecf20Sopenharmony_ci (file->f_flags & O_NONBLOCK)) 5768c2ecf20Sopenharmony_ci return -EAGAIN; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* 5798c2ecf20Sopenharmony_ci * count == 0 is special - no IO is done but we check 5808c2ecf20Sopenharmony_ci * for error conditions (see above). 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ci if (count == 0) 5838c2ecf20Sopenharmony_ci break; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci while (read + input_event_size() <= count && 5868c2ecf20Sopenharmony_ci evdev_fetch_next_event(client, &event)) { 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (input_event_to_user(buffer + read, &event)) 5898c2ecf20Sopenharmony_ci return -EFAULT; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci read += input_event_size(); 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (read) 5958c2ecf20Sopenharmony_ci break; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (!(file->f_flags & O_NONBLOCK)) { 5988c2ecf20Sopenharmony_ci error = wait_event_interruptible(client->wait, 5998c2ecf20Sopenharmony_ci client->packet_head != client->tail || 6008c2ecf20Sopenharmony_ci !evdev->exist || client->revoked); 6018c2ecf20Sopenharmony_ci if (error) 6028c2ecf20Sopenharmony_ci return error; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci return read; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci/* No kernel lock - fine */ 6108c2ecf20Sopenharmony_cistatic __poll_t evdev_poll(struct file *file, poll_table *wait) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct evdev_client *client = file->private_data; 6138c2ecf20Sopenharmony_ci struct evdev *evdev = client->evdev; 6148c2ecf20Sopenharmony_ci __poll_t mask; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci poll_wait(file, &client->wait, wait); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (evdev->exist && !client->revoked) 6198c2ecf20Sopenharmony_ci mask = EPOLLOUT | EPOLLWRNORM; 6208c2ecf20Sopenharmony_ci else 6218c2ecf20Sopenharmony_ci mask = EPOLLHUP | EPOLLERR; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (client->packet_head != client->tail) 6248c2ecf20Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci return mask; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) 6328c2ecf20Sopenharmony_ci#define BITS_TO_LONGS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1) 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 6358c2ecf20Sopenharmony_cistatic int bits_to_user(unsigned long *bits, unsigned int maxbit, 6368c2ecf20Sopenharmony_ci unsigned int maxlen, void __user *p, int compat) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci int len, i; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (compat) { 6418c2ecf20Sopenharmony_ci len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t); 6428c2ecf20Sopenharmony_ci if (len > maxlen) 6438c2ecf20Sopenharmony_ci len = maxlen; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci for (i = 0; i < len / sizeof(compat_long_t); i++) 6468c2ecf20Sopenharmony_ci if (copy_to_user((compat_long_t __user *) p + i, 6478c2ecf20Sopenharmony_ci (compat_long_t *) bits + 6488c2ecf20Sopenharmony_ci i + 1 - ((i % 2) << 1), 6498c2ecf20Sopenharmony_ci sizeof(compat_long_t))) 6508c2ecf20Sopenharmony_ci return -EFAULT; 6518c2ecf20Sopenharmony_ci } else { 6528c2ecf20Sopenharmony_ci len = BITS_TO_LONGS(maxbit) * sizeof(long); 6538c2ecf20Sopenharmony_ci if (len > maxlen) 6548c2ecf20Sopenharmony_ci len = maxlen; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (copy_to_user(p, bits, len)) 6578c2ecf20Sopenharmony_ci return -EFAULT; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return len; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int bits_from_user(unsigned long *bits, unsigned int maxbit, 6648c2ecf20Sopenharmony_ci unsigned int maxlen, const void __user *p, int compat) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci int len, i; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci if (compat) { 6698c2ecf20Sopenharmony_ci if (maxlen % sizeof(compat_long_t)) 6708c2ecf20Sopenharmony_ci return -EINVAL; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t); 6738c2ecf20Sopenharmony_ci if (len > maxlen) 6748c2ecf20Sopenharmony_ci len = maxlen; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci for (i = 0; i < len / sizeof(compat_long_t); i++) 6778c2ecf20Sopenharmony_ci if (copy_from_user((compat_long_t *) bits + 6788c2ecf20Sopenharmony_ci i + 1 - ((i % 2) << 1), 6798c2ecf20Sopenharmony_ci (compat_long_t __user *) p + i, 6808c2ecf20Sopenharmony_ci sizeof(compat_long_t))) 6818c2ecf20Sopenharmony_ci return -EFAULT; 6828c2ecf20Sopenharmony_ci if (i % 2) 6838c2ecf20Sopenharmony_ci *((compat_long_t *) bits + i - 1) = 0; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci } else { 6868c2ecf20Sopenharmony_ci if (maxlen % sizeof(long)) 6878c2ecf20Sopenharmony_ci return -EINVAL; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci len = BITS_TO_LONGS(maxbit) * sizeof(long); 6908c2ecf20Sopenharmony_ci if (len > maxlen) 6918c2ecf20Sopenharmony_ci len = maxlen; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (copy_from_user(bits, p, len)) 6948c2ecf20Sopenharmony_ci return -EFAULT; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci return len; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci#else 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic int bits_to_user(unsigned long *bits, unsigned int maxbit, 7038c2ecf20Sopenharmony_ci unsigned int maxlen, void __user *p, int compat) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci int len = compat ? 7068c2ecf20Sopenharmony_ci BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t) : 7078c2ecf20Sopenharmony_ci BITS_TO_LONGS(maxbit) * sizeof(long); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (len > maxlen) 7108c2ecf20Sopenharmony_ci len = maxlen; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci return copy_to_user(p, bits, len) ? -EFAULT : len; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic int bits_from_user(unsigned long *bits, unsigned int maxbit, 7168c2ecf20Sopenharmony_ci unsigned int maxlen, const void __user *p, int compat) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci size_t chunk_size = compat ? sizeof(compat_long_t) : sizeof(long); 7198c2ecf20Sopenharmony_ci int len; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (maxlen % chunk_size) 7228c2ecf20Sopenharmony_ci return -EINVAL; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci len = compat ? BITS_TO_LONGS_COMPAT(maxbit) : BITS_TO_LONGS(maxbit); 7258c2ecf20Sopenharmony_ci len *= chunk_size; 7268c2ecf20Sopenharmony_ci if (len > maxlen) 7278c2ecf20Sopenharmony_ci len = maxlen; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return copy_from_user(bits, p, len) ? -EFAULT : len; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci#endif /* __BIG_ENDIAN */ 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci#else 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic int bits_to_user(unsigned long *bits, unsigned int maxbit, 7378c2ecf20Sopenharmony_ci unsigned int maxlen, void __user *p, int compat) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci int len = BITS_TO_LONGS(maxbit) * sizeof(long); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (len > maxlen) 7428c2ecf20Sopenharmony_ci len = maxlen; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci return copy_to_user(p, bits, len) ? -EFAULT : len; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic int bits_from_user(unsigned long *bits, unsigned int maxbit, 7488c2ecf20Sopenharmony_ci unsigned int maxlen, const void __user *p, int compat) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci int len; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (maxlen % sizeof(long)) 7538c2ecf20Sopenharmony_ci return -EINVAL; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci len = BITS_TO_LONGS(maxbit) * sizeof(long); 7568c2ecf20Sopenharmony_ci if (len > maxlen) 7578c2ecf20Sopenharmony_ci len = maxlen; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci return copy_from_user(bits, p, len) ? -EFAULT : len; 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci#endif /* CONFIG_COMPAT */ 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic int str_to_user(const char *str, unsigned int maxlen, void __user *p) 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci int len; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (!str) 7698c2ecf20Sopenharmony_ci return -ENOENT; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci len = strlen(str) + 1; 7728c2ecf20Sopenharmony_ci if (len > maxlen) 7738c2ecf20Sopenharmony_ci len = maxlen; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci return copy_to_user(p, str, len) ? -EFAULT : len; 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_cistatic int handle_eviocgbit(struct input_dev *dev, 7798c2ecf20Sopenharmony_ci unsigned int type, unsigned int size, 7808c2ecf20Sopenharmony_ci void __user *p, int compat_mode) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci unsigned long *bits; 7838c2ecf20Sopenharmony_ci int len; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci switch (type) { 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci case 0: bits = dev->evbit; len = EV_MAX; break; 7888c2ecf20Sopenharmony_ci case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; 7898c2ecf20Sopenharmony_ci case EV_REL: bits = dev->relbit; len = REL_MAX; break; 7908c2ecf20Sopenharmony_ci case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; 7918c2ecf20Sopenharmony_ci case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; 7928c2ecf20Sopenharmony_ci case EV_LED: bits = dev->ledbit; len = LED_MAX; break; 7938c2ecf20Sopenharmony_ci case EV_SND: bits = dev->sndbit; len = SND_MAX; break; 7948c2ecf20Sopenharmony_ci case EV_FF: bits = dev->ffbit; len = FF_MAX; break; 7958c2ecf20Sopenharmony_ci case EV_SW: bits = dev->swbit; len = SW_MAX; break; 7968c2ecf20Sopenharmony_ci default: return -EINVAL; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci return bits_to_user(bits, len, size, p, compat_mode); 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic int evdev_handle_get_keycode(struct input_dev *dev, void __user *p) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci struct input_keymap_entry ke = { 8058c2ecf20Sopenharmony_ci .len = sizeof(unsigned int), 8068c2ecf20Sopenharmony_ci .flags = 0, 8078c2ecf20Sopenharmony_ci }; 8088c2ecf20Sopenharmony_ci int __user *ip = (int __user *)p; 8098c2ecf20Sopenharmony_ci int error; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci /* legacy case */ 8128c2ecf20Sopenharmony_ci if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) 8138c2ecf20Sopenharmony_ci return -EFAULT; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci error = input_get_keycode(dev, &ke); 8168c2ecf20Sopenharmony_ci if (error) 8178c2ecf20Sopenharmony_ci return error; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (put_user(ke.keycode, ip + 1)) 8208c2ecf20Sopenharmony_ci return -EFAULT; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci return 0; 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic int evdev_handle_get_keycode_v2(struct input_dev *dev, void __user *p) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci struct input_keymap_entry ke; 8288c2ecf20Sopenharmony_ci int error; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (copy_from_user(&ke, p, sizeof(ke))) 8318c2ecf20Sopenharmony_ci return -EFAULT; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci error = input_get_keycode(dev, &ke); 8348c2ecf20Sopenharmony_ci if (error) 8358c2ecf20Sopenharmony_ci return error; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (copy_to_user(p, &ke, sizeof(ke))) 8388c2ecf20Sopenharmony_ci return -EFAULT; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci return 0; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic int evdev_handle_set_keycode(struct input_dev *dev, void __user *p) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci struct input_keymap_entry ke = { 8468c2ecf20Sopenharmony_ci .len = sizeof(unsigned int), 8478c2ecf20Sopenharmony_ci .flags = 0, 8488c2ecf20Sopenharmony_ci }; 8498c2ecf20Sopenharmony_ci int __user *ip = (int __user *)p; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) 8528c2ecf20Sopenharmony_ci return -EFAULT; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci if (get_user(ke.keycode, ip + 1)) 8558c2ecf20Sopenharmony_ci return -EFAULT; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci return input_set_keycode(dev, &ke); 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci struct input_keymap_entry ke; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (copy_from_user(&ke, p, sizeof(ke))) 8658c2ecf20Sopenharmony_ci return -EFAULT; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (ke.len > sizeof(ke.scancode)) 8688c2ecf20Sopenharmony_ci return -EINVAL; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci return input_set_keycode(dev, &ke); 8718c2ecf20Sopenharmony_ci} 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci/* 8748c2ecf20Sopenharmony_ci * If we transfer state to the user, we should flush all pending events 8758c2ecf20Sopenharmony_ci * of the same type from the client's queue. Otherwise, they might end up 8768c2ecf20Sopenharmony_ci * with duplicate events, which can screw up client's state tracking. 8778c2ecf20Sopenharmony_ci * If bits_to_user fails after flushing the queue, we queue a SYN_DROPPED 8788c2ecf20Sopenharmony_ci * event so user-space will notice missing events. 8798c2ecf20Sopenharmony_ci * 8808c2ecf20Sopenharmony_ci * LOCKING: 8818c2ecf20Sopenharmony_ci * We need to take event_lock before buffer_lock to avoid dead-locks. But we 8828c2ecf20Sopenharmony_ci * need the even_lock only to guarantee consistent state. We can safely release 8838c2ecf20Sopenharmony_ci * it while flushing the queue. This allows input-core to handle filters while 8848c2ecf20Sopenharmony_ci * we flush the queue. 8858c2ecf20Sopenharmony_ci */ 8868c2ecf20Sopenharmony_cistatic int evdev_handle_get_val(struct evdev_client *client, 8878c2ecf20Sopenharmony_ci struct input_dev *dev, unsigned int type, 8888c2ecf20Sopenharmony_ci unsigned long *bits, unsigned int maxbit, 8898c2ecf20Sopenharmony_ci unsigned int maxlen, void __user *p, 8908c2ecf20Sopenharmony_ci int compat) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci int ret; 8938c2ecf20Sopenharmony_ci unsigned long *mem; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci mem = bitmap_alloc(maxbit, GFP_KERNEL); 8968c2ecf20Sopenharmony_ci if (!mem) 8978c2ecf20Sopenharmony_ci return -ENOMEM; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci spin_lock_irq(&dev->event_lock); 9008c2ecf20Sopenharmony_ci spin_lock(&client->buffer_lock); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci bitmap_copy(mem, bits, maxbit); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci spin_unlock(&dev->event_lock); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci __evdev_flush_queue(client, type); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci spin_unlock_irq(&client->buffer_lock); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci ret = bits_to_user(mem, maxbit, maxlen, p, compat); 9118c2ecf20Sopenharmony_ci if (ret < 0) 9128c2ecf20Sopenharmony_ci evdev_queue_syn_dropped(client); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci bitmap_free(mem); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci return ret; 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cistatic int evdev_handle_mt_request(struct input_dev *dev, 9208c2ecf20Sopenharmony_ci unsigned int size, 9218c2ecf20Sopenharmony_ci int __user *ip) 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci const struct input_mt *mt = dev->mt; 9248c2ecf20Sopenharmony_ci unsigned int code; 9258c2ecf20Sopenharmony_ci int max_slots; 9268c2ecf20Sopenharmony_ci int i; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (get_user(code, &ip[0])) 9298c2ecf20Sopenharmony_ci return -EFAULT; 9308c2ecf20Sopenharmony_ci if (!mt || !input_is_mt_value(code)) 9318c2ecf20Sopenharmony_ci return -EINVAL; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci max_slots = (size - sizeof(__u32)) / sizeof(__s32); 9348c2ecf20Sopenharmony_ci for (i = 0; i < mt->num_slots && i < max_slots; i++) { 9358c2ecf20Sopenharmony_ci int value = input_mt_get_value(&mt->slots[i], code); 9368c2ecf20Sopenharmony_ci if (put_user(value, &ip[1 + i])) 9378c2ecf20Sopenharmony_ci return -EFAULT; 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci return 0; 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cistatic int evdev_revoke(struct evdev *evdev, struct evdev_client *client, 9448c2ecf20Sopenharmony_ci struct file *file) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci client->revoked = true; 9478c2ecf20Sopenharmony_ci evdev_ungrab(evdev, client); 9488c2ecf20Sopenharmony_ci input_flush_device(&evdev->handle, file); 9498c2ecf20Sopenharmony_ci wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci return 0; 9528c2ecf20Sopenharmony_ci} 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci/* must be called with evdev-mutex held */ 9558c2ecf20Sopenharmony_cistatic int evdev_set_mask(struct evdev_client *client, 9568c2ecf20Sopenharmony_ci unsigned int type, 9578c2ecf20Sopenharmony_ci const void __user *codes, 9588c2ecf20Sopenharmony_ci u32 codes_size, 9598c2ecf20Sopenharmony_ci int compat) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci unsigned long flags, *mask, *oldmask; 9628c2ecf20Sopenharmony_ci size_t cnt; 9638c2ecf20Sopenharmony_ci int error; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci /* we allow unknown types and 'codes_size > size' for forward-compat */ 9668c2ecf20Sopenharmony_ci cnt = evdev_get_mask_cnt(type); 9678c2ecf20Sopenharmony_ci if (!cnt) 9688c2ecf20Sopenharmony_ci return 0; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci mask = bitmap_zalloc(cnt, GFP_KERNEL); 9718c2ecf20Sopenharmony_ci if (!mask) 9728c2ecf20Sopenharmony_ci return -ENOMEM; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci error = bits_from_user(mask, cnt - 1, codes_size, codes, compat); 9758c2ecf20Sopenharmony_ci if (error < 0) { 9768c2ecf20Sopenharmony_ci bitmap_free(mask); 9778c2ecf20Sopenharmony_ci return error; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci spin_lock_irqsave(&client->buffer_lock, flags); 9818c2ecf20Sopenharmony_ci oldmask = client->evmasks[type]; 9828c2ecf20Sopenharmony_ci client->evmasks[type] = mask; 9838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&client->buffer_lock, flags); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci bitmap_free(oldmask); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci return 0; 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci/* must be called with evdev-mutex held */ 9918c2ecf20Sopenharmony_cistatic int evdev_get_mask(struct evdev_client *client, 9928c2ecf20Sopenharmony_ci unsigned int type, 9938c2ecf20Sopenharmony_ci void __user *codes, 9948c2ecf20Sopenharmony_ci u32 codes_size, 9958c2ecf20Sopenharmony_ci int compat) 9968c2ecf20Sopenharmony_ci{ 9978c2ecf20Sopenharmony_ci unsigned long *mask; 9988c2ecf20Sopenharmony_ci size_t cnt, size, xfer_size; 9998c2ecf20Sopenharmony_ci int i; 10008c2ecf20Sopenharmony_ci int error; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci /* we allow unknown types and 'codes_size > size' for forward-compat */ 10038c2ecf20Sopenharmony_ci cnt = evdev_get_mask_cnt(type); 10048c2ecf20Sopenharmony_ci size = sizeof(unsigned long) * BITS_TO_LONGS(cnt); 10058c2ecf20Sopenharmony_ci xfer_size = min_t(size_t, codes_size, size); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (cnt > 0) { 10088c2ecf20Sopenharmony_ci mask = client->evmasks[type]; 10098c2ecf20Sopenharmony_ci if (mask) { 10108c2ecf20Sopenharmony_ci error = bits_to_user(mask, cnt - 1, 10118c2ecf20Sopenharmony_ci xfer_size, codes, compat); 10128c2ecf20Sopenharmony_ci if (error < 0) 10138c2ecf20Sopenharmony_ci return error; 10148c2ecf20Sopenharmony_ci } else { 10158c2ecf20Sopenharmony_ci /* fake mask with all bits set */ 10168c2ecf20Sopenharmony_ci for (i = 0; i < xfer_size; i++) 10178c2ecf20Sopenharmony_ci if (put_user(0xffU, (u8 __user *)codes + i)) 10188c2ecf20Sopenharmony_ci return -EFAULT; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (xfer_size < codes_size) 10238c2ecf20Sopenharmony_ci if (clear_user(codes + xfer_size, codes_size - xfer_size)) 10248c2ecf20Sopenharmony_ci return -EFAULT; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci return 0; 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic long evdev_do_ioctl(struct file *file, unsigned int cmd, 10308c2ecf20Sopenharmony_ci void __user *p, int compat_mode) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci struct evdev_client *client = file->private_data; 10338c2ecf20Sopenharmony_ci struct evdev *evdev = client->evdev; 10348c2ecf20Sopenharmony_ci struct input_dev *dev = evdev->handle.dev; 10358c2ecf20Sopenharmony_ci struct input_absinfo abs; 10368c2ecf20Sopenharmony_ci struct input_mask mask; 10378c2ecf20Sopenharmony_ci struct ff_effect effect; 10388c2ecf20Sopenharmony_ci int __user *ip = (int __user *)p; 10398c2ecf20Sopenharmony_ci unsigned int i, t, u, v; 10408c2ecf20Sopenharmony_ci unsigned int size; 10418c2ecf20Sopenharmony_ci int error; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* First we check for fixed-length commands */ 10448c2ecf20Sopenharmony_ci switch (cmd) { 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci case EVIOCGVERSION: 10478c2ecf20Sopenharmony_ci return put_user(EV_VERSION, ip); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci case EVIOCGID: 10508c2ecf20Sopenharmony_ci if (copy_to_user(p, &dev->id, sizeof(struct input_id))) 10518c2ecf20Sopenharmony_ci return -EFAULT; 10528c2ecf20Sopenharmony_ci return 0; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci case EVIOCGREP: 10558c2ecf20Sopenharmony_ci if (!test_bit(EV_REP, dev->evbit)) 10568c2ecf20Sopenharmony_ci return -ENOSYS; 10578c2ecf20Sopenharmony_ci if (put_user(dev->rep[REP_DELAY], ip)) 10588c2ecf20Sopenharmony_ci return -EFAULT; 10598c2ecf20Sopenharmony_ci if (put_user(dev->rep[REP_PERIOD], ip + 1)) 10608c2ecf20Sopenharmony_ci return -EFAULT; 10618c2ecf20Sopenharmony_ci return 0; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci case EVIOCSREP: 10648c2ecf20Sopenharmony_ci if (!test_bit(EV_REP, dev->evbit)) 10658c2ecf20Sopenharmony_ci return -ENOSYS; 10668c2ecf20Sopenharmony_ci if (get_user(u, ip)) 10678c2ecf20Sopenharmony_ci return -EFAULT; 10688c2ecf20Sopenharmony_ci if (get_user(v, ip + 1)) 10698c2ecf20Sopenharmony_ci return -EFAULT; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u); 10728c2ecf20Sopenharmony_ci input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci return 0; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci case EVIOCRMFF: 10778c2ecf20Sopenharmony_ci return input_ff_erase(dev, (int)(unsigned long) p, file); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci case EVIOCGEFFECTS: 10808c2ecf20Sopenharmony_ci i = test_bit(EV_FF, dev->evbit) ? 10818c2ecf20Sopenharmony_ci dev->ff->max_effects : 0; 10828c2ecf20Sopenharmony_ci if (put_user(i, ip)) 10838c2ecf20Sopenharmony_ci return -EFAULT; 10848c2ecf20Sopenharmony_ci return 0; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci case EVIOCGRAB: 10878c2ecf20Sopenharmony_ci if (p) 10888c2ecf20Sopenharmony_ci return evdev_grab(evdev, client); 10898c2ecf20Sopenharmony_ci else 10908c2ecf20Sopenharmony_ci return evdev_ungrab(evdev, client); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci case EVIOCREVOKE: 10938c2ecf20Sopenharmony_ci if (p) 10948c2ecf20Sopenharmony_ci return -EINVAL; 10958c2ecf20Sopenharmony_ci else 10968c2ecf20Sopenharmony_ci return evdev_revoke(evdev, client, file); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci case EVIOCGMASK: { 10998c2ecf20Sopenharmony_ci void __user *codes_ptr; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci if (copy_from_user(&mask, p, sizeof(mask))) 11028c2ecf20Sopenharmony_ci return -EFAULT; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci codes_ptr = (void __user *)(unsigned long)mask.codes_ptr; 11058c2ecf20Sopenharmony_ci return evdev_get_mask(client, 11068c2ecf20Sopenharmony_ci mask.type, codes_ptr, mask.codes_size, 11078c2ecf20Sopenharmony_ci compat_mode); 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci case EVIOCSMASK: { 11118c2ecf20Sopenharmony_ci const void __user *codes_ptr; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if (copy_from_user(&mask, p, sizeof(mask))) 11148c2ecf20Sopenharmony_ci return -EFAULT; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci codes_ptr = (const void __user *)(unsigned long)mask.codes_ptr; 11178c2ecf20Sopenharmony_ci return evdev_set_mask(client, 11188c2ecf20Sopenharmony_ci mask.type, codes_ptr, mask.codes_size, 11198c2ecf20Sopenharmony_ci compat_mode); 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci case EVIOCSCLOCKID: 11238c2ecf20Sopenharmony_ci if (copy_from_user(&i, p, sizeof(unsigned int))) 11248c2ecf20Sopenharmony_ci return -EFAULT; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci return evdev_set_clk_type(client, i); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci case EVIOCGKEYCODE: 11298c2ecf20Sopenharmony_ci return evdev_handle_get_keycode(dev, p); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci case EVIOCSKEYCODE: 11328c2ecf20Sopenharmony_ci return evdev_handle_set_keycode(dev, p); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci case EVIOCGKEYCODE_V2: 11358c2ecf20Sopenharmony_ci return evdev_handle_get_keycode_v2(dev, p); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci case EVIOCSKEYCODE_V2: 11388c2ecf20Sopenharmony_ci return evdev_handle_set_keycode_v2(dev, p); 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci size = _IOC_SIZE(cmd); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci /* Now check variable-length commands */ 11448c2ecf20Sopenharmony_ci#define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) 11458c2ecf20Sopenharmony_ci switch (EVIOC_MASK_SIZE(cmd)) { 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci case EVIOCGPROP(0): 11488c2ecf20Sopenharmony_ci return bits_to_user(dev->propbit, INPUT_PROP_MAX, 11498c2ecf20Sopenharmony_ci size, p, compat_mode); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci case EVIOCGMTSLOTS(0): 11528c2ecf20Sopenharmony_ci return evdev_handle_mt_request(dev, size, ip); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci case EVIOCGKEY(0): 11558c2ecf20Sopenharmony_ci return evdev_handle_get_val(client, dev, EV_KEY, dev->key, 11568c2ecf20Sopenharmony_ci KEY_MAX, size, p, compat_mode); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci case EVIOCGLED(0): 11598c2ecf20Sopenharmony_ci return evdev_handle_get_val(client, dev, EV_LED, dev->led, 11608c2ecf20Sopenharmony_ci LED_MAX, size, p, compat_mode); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci case EVIOCGSND(0): 11638c2ecf20Sopenharmony_ci return evdev_handle_get_val(client, dev, EV_SND, dev->snd, 11648c2ecf20Sopenharmony_ci SND_MAX, size, p, compat_mode); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci case EVIOCGSW(0): 11678c2ecf20Sopenharmony_ci return evdev_handle_get_val(client, dev, EV_SW, dev->sw, 11688c2ecf20Sopenharmony_ci SW_MAX, size, p, compat_mode); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci case EVIOCGNAME(0): 11718c2ecf20Sopenharmony_ci return str_to_user(dev->name, size, p); 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci case EVIOCGPHYS(0): 11748c2ecf20Sopenharmony_ci return str_to_user(dev->phys, size, p); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci case EVIOCGUNIQ(0): 11778c2ecf20Sopenharmony_ci return str_to_user(dev->uniq, size, p); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci case EVIOC_MASK_SIZE(EVIOCSFF): 11808c2ecf20Sopenharmony_ci if (input_ff_effect_from_user(p, size, &effect)) 11818c2ecf20Sopenharmony_ci return -EFAULT; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci error = input_ff_upload(dev, &effect, file); 11848c2ecf20Sopenharmony_ci if (error) 11858c2ecf20Sopenharmony_ci return error; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) 11888c2ecf20Sopenharmony_ci return -EFAULT; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci return 0; 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci /* Multi-number variable-length handlers */ 11948c2ecf20Sopenharmony_ci if (_IOC_TYPE(cmd) != 'E') 11958c2ecf20Sopenharmony_ci return -EINVAL; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci if (_IOC_DIR(cmd) == _IOC_READ) { 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) 12008c2ecf20Sopenharmony_ci return handle_eviocgbit(dev, 12018c2ecf20Sopenharmony_ci _IOC_NR(cmd) & EV_MAX, size, 12028c2ecf20Sopenharmony_ci p, compat_mode); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (!dev->absinfo) 12078c2ecf20Sopenharmony_ci return -EINVAL; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci t = _IOC_NR(cmd) & ABS_MAX; 12108c2ecf20Sopenharmony_ci abs = dev->absinfo[t]; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci if (copy_to_user(p, &abs, min_t(size_t, 12138c2ecf20Sopenharmony_ci size, sizeof(struct input_absinfo)))) 12148c2ecf20Sopenharmony_ci return -EFAULT; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci return 0; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci if (_IOC_DIR(cmd) == _IOC_WRITE) { 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (!dev->absinfo) 12258c2ecf20Sopenharmony_ci return -EINVAL; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci t = _IOC_NR(cmd) & ABS_MAX; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci if (copy_from_user(&abs, p, min_t(size_t, 12308c2ecf20Sopenharmony_ci size, sizeof(struct input_absinfo)))) 12318c2ecf20Sopenharmony_ci return -EFAULT; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (size < sizeof(struct input_absinfo)) 12348c2ecf20Sopenharmony_ci abs.resolution = 0; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci /* We can't change number of reserved MT slots */ 12378c2ecf20Sopenharmony_ci if (t == ABS_MT_SLOT) 12388c2ecf20Sopenharmony_ci return -EINVAL; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci /* 12418c2ecf20Sopenharmony_ci * Take event lock to ensure that we are not 12428c2ecf20Sopenharmony_ci * changing device parameters in the middle 12438c2ecf20Sopenharmony_ci * of event. 12448c2ecf20Sopenharmony_ci */ 12458c2ecf20Sopenharmony_ci spin_lock_irq(&dev->event_lock); 12468c2ecf20Sopenharmony_ci dev->absinfo[t] = abs; 12478c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->event_lock); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci return 0; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci return -EINVAL; 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cistatic long evdev_ioctl_handler(struct file *file, unsigned int cmd, 12578c2ecf20Sopenharmony_ci void __user *p, int compat_mode) 12588c2ecf20Sopenharmony_ci{ 12598c2ecf20Sopenharmony_ci struct evdev_client *client = file->private_data; 12608c2ecf20Sopenharmony_ci struct evdev *evdev = client->evdev; 12618c2ecf20Sopenharmony_ci int retval; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci retval = mutex_lock_interruptible(&evdev->mutex); 12648c2ecf20Sopenharmony_ci if (retval) 12658c2ecf20Sopenharmony_ci return retval; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci if (!evdev->exist || client->revoked) { 12688c2ecf20Sopenharmony_ci retval = -ENODEV; 12698c2ecf20Sopenharmony_ci goto out; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci retval = evdev_do_ioctl(file, cmd, p, compat_mode); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci out: 12758c2ecf20Sopenharmony_ci mutex_unlock(&evdev->mutex); 12768c2ecf20Sopenharmony_ci return retval; 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistatic long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0); 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 12858c2ecf20Sopenharmony_cistatic long evdev_ioctl_compat(struct file *file, 12868c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1); 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci#endif 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_cistatic const struct file_operations evdev_fops = { 12938c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 12948c2ecf20Sopenharmony_ci .read = evdev_read, 12958c2ecf20Sopenharmony_ci .write = evdev_write, 12968c2ecf20Sopenharmony_ci .poll = evdev_poll, 12978c2ecf20Sopenharmony_ci .open = evdev_open, 12988c2ecf20Sopenharmony_ci .release = evdev_release, 12998c2ecf20Sopenharmony_ci .unlocked_ioctl = evdev_ioctl, 13008c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 13018c2ecf20Sopenharmony_ci .compat_ioctl = evdev_ioctl_compat, 13028c2ecf20Sopenharmony_ci#endif 13038c2ecf20Sopenharmony_ci .fasync = evdev_fasync, 13048c2ecf20Sopenharmony_ci .llseek = no_llseek, 13058c2ecf20Sopenharmony_ci}; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci/* 13088c2ecf20Sopenharmony_ci * Mark device non-existent. This disables writes, ioctls and 13098c2ecf20Sopenharmony_ci * prevents new users from opening the device. Already posted 13108c2ecf20Sopenharmony_ci * blocking reads will stay, however new ones will fail. 13118c2ecf20Sopenharmony_ci */ 13128c2ecf20Sopenharmony_cistatic void evdev_mark_dead(struct evdev *evdev) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci mutex_lock(&evdev->mutex); 13158c2ecf20Sopenharmony_ci evdev->exist = false; 13168c2ecf20Sopenharmony_ci mutex_unlock(&evdev->mutex); 13178c2ecf20Sopenharmony_ci} 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cistatic void evdev_cleanup(struct evdev *evdev) 13208c2ecf20Sopenharmony_ci{ 13218c2ecf20Sopenharmony_ci struct input_handle *handle = &evdev->handle; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci evdev_mark_dead(evdev); 13248c2ecf20Sopenharmony_ci evdev_hangup(evdev); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci /* evdev is marked dead so no one else accesses evdev->open */ 13278c2ecf20Sopenharmony_ci if (evdev->open) { 13288c2ecf20Sopenharmony_ci input_flush_device(handle, NULL); 13298c2ecf20Sopenharmony_ci input_close_device(handle); 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci} 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci/* 13348c2ecf20Sopenharmony_ci * Create new evdev device. Note that input core serializes calls 13358c2ecf20Sopenharmony_ci * to connect and disconnect. 13368c2ecf20Sopenharmony_ci */ 13378c2ecf20Sopenharmony_cistatic int evdev_connect(struct input_handler *handler, struct input_dev *dev, 13388c2ecf20Sopenharmony_ci const struct input_device_id *id) 13398c2ecf20Sopenharmony_ci{ 13408c2ecf20Sopenharmony_ci struct evdev *evdev; 13418c2ecf20Sopenharmony_ci int minor; 13428c2ecf20Sopenharmony_ci int dev_no; 13438c2ecf20Sopenharmony_ci int error; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true); 13468c2ecf20Sopenharmony_ci if (minor < 0) { 13478c2ecf20Sopenharmony_ci error = minor; 13488c2ecf20Sopenharmony_ci pr_err("failed to reserve new minor: %d\n", error); 13498c2ecf20Sopenharmony_ci return error; 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); 13538c2ecf20Sopenharmony_ci if (!evdev) { 13548c2ecf20Sopenharmony_ci error = -ENOMEM; 13558c2ecf20Sopenharmony_ci goto err_free_minor; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&evdev->client_list); 13598c2ecf20Sopenharmony_ci spin_lock_init(&evdev->client_lock); 13608c2ecf20Sopenharmony_ci mutex_init(&evdev->mutex); 13618c2ecf20Sopenharmony_ci evdev->exist = true; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci dev_no = minor; 13648c2ecf20Sopenharmony_ci /* Normalize device number if it falls into legacy range */ 13658c2ecf20Sopenharmony_ci if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS) 13668c2ecf20Sopenharmony_ci dev_no -= EVDEV_MINOR_BASE; 13678c2ecf20Sopenharmony_ci dev_set_name(&evdev->dev, "event%d", dev_no); 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci evdev->handle.dev = input_get_device(dev); 13708c2ecf20Sopenharmony_ci evdev->handle.name = dev_name(&evdev->dev); 13718c2ecf20Sopenharmony_ci evdev->handle.handler = handler; 13728c2ecf20Sopenharmony_ci evdev->handle.private = evdev; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci evdev->dev.devt = MKDEV(INPUT_MAJOR, minor); 13758c2ecf20Sopenharmony_ci evdev->dev.class = &input_class; 13768c2ecf20Sopenharmony_ci evdev->dev.parent = &dev->dev; 13778c2ecf20Sopenharmony_ci evdev->dev.release = evdev_free; 13788c2ecf20Sopenharmony_ci device_initialize(&evdev->dev); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci error = input_register_handle(&evdev->handle); 13818c2ecf20Sopenharmony_ci if (error) 13828c2ecf20Sopenharmony_ci goto err_free_evdev; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci cdev_init(&evdev->cdev, &evdev_fops); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci error = cdev_device_add(&evdev->cdev, &evdev->dev); 13878c2ecf20Sopenharmony_ci if (error) 13888c2ecf20Sopenharmony_ci goto err_cleanup_evdev; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci return 0; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci err_cleanup_evdev: 13938c2ecf20Sopenharmony_ci evdev_cleanup(evdev); 13948c2ecf20Sopenharmony_ci input_unregister_handle(&evdev->handle); 13958c2ecf20Sopenharmony_ci err_free_evdev: 13968c2ecf20Sopenharmony_ci put_device(&evdev->dev); 13978c2ecf20Sopenharmony_ci err_free_minor: 13988c2ecf20Sopenharmony_ci input_free_minor(minor); 13998c2ecf20Sopenharmony_ci return error; 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic void evdev_disconnect(struct input_handle *handle) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci struct evdev *evdev = handle->private; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci cdev_device_del(&evdev->cdev, &evdev->dev); 14078c2ecf20Sopenharmony_ci evdev_cleanup(evdev); 14088c2ecf20Sopenharmony_ci input_free_minor(MINOR(evdev->dev.devt)); 14098c2ecf20Sopenharmony_ci input_unregister_handle(handle); 14108c2ecf20Sopenharmony_ci put_device(&evdev->dev); 14118c2ecf20Sopenharmony_ci} 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_cistatic const struct input_device_id evdev_ids[] = { 14148c2ecf20Sopenharmony_ci { .driver_info = 1 }, /* Matches all devices */ 14158c2ecf20Sopenharmony_ci { }, /* Terminating zero entry */ 14168c2ecf20Sopenharmony_ci}; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(input, evdev_ids); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_cistatic struct input_handler evdev_handler = { 14218c2ecf20Sopenharmony_ci .event = evdev_event, 14228c2ecf20Sopenharmony_ci .events = evdev_events, 14238c2ecf20Sopenharmony_ci .connect = evdev_connect, 14248c2ecf20Sopenharmony_ci .disconnect = evdev_disconnect, 14258c2ecf20Sopenharmony_ci .legacy_minors = true, 14268c2ecf20Sopenharmony_ci .minor = EVDEV_MINOR_BASE, 14278c2ecf20Sopenharmony_ci .name = "evdev", 14288c2ecf20Sopenharmony_ci .id_table = evdev_ids, 14298c2ecf20Sopenharmony_ci}; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_cistatic int __init evdev_init(void) 14328c2ecf20Sopenharmony_ci{ 14338c2ecf20Sopenharmony_ci return input_register_handler(&evdev_handler); 14348c2ecf20Sopenharmony_ci} 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_cistatic void __exit evdev_exit(void) 14378c2ecf20Sopenharmony_ci{ 14388c2ecf20Sopenharmony_ci input_unregister_handler(&evdev_handler); 14398c2ecf20Sopenharmony_ci} 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_cimodule_init(evdev_init); 14428c2ecf20Sopenharmony_cimodule_exit(evdev_exit); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 14458c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Input driver event char devices"); 14468c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1447