/* * Event char devices, giving access to raw input device events. * * Copyright (c) 1999-2002 Vojtech Pavlik * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define EVDEV_MINOR_BASE 64#define EVDEV_MINORS 32#define EVDEV_MIN_BUFFER_SIZE 64U#define EVDEV_BUF_PACKETS 8 #include <linux/poll.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/init.h>#include <linux/input/mt.h>#include <linux/major.h>#include <linux/device.h>#include <linux/cdev.h>#include "input-compat.h" struct evdev { int open; struct input_handle handle; wait_queue_head_t wait; struct evdev_client __rcu *grab; struct list_head client_list; spinlock_t client_lock; /* protects client_list */ struct mutex mutex; struct device dev; struct cdev cdev; bool exist;}; struct evdev_client { unsigned int head; unsigned int tail; unsigned int packet_head; /* [future] position of the first element of next packet */ spinlock_t buffer_lock; /* protects access to buffer, head and tail */ struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; int clkid; unsigned int bufsize; struct input_event buffer[];}; /* flush queued events of type @type, caller must hold client->buffer_lock */static void __evdev_flush_queue(struct evdev_client *client, unsigned int type){ unsigned int i, head, num; unsigned int mask = client->bufsize - 1; bool is_report; struct input_event *ev; BUG_ON(type == EV_SYN); head = client->tail; client->packet_head = client->tail; /* init to 1 so a leading SYN_REPORT will not be dropped */ num = 1; for (i = client->tail; i != client->head; i = (i + 1) & mask) { ev = &client->buffer[i]; is_report = ev->type == EV_SYN && ev->code == SYN_REPORT; if (ev->type == type) { /* drop matched entry */ continue; } else if (is_report && !num) { /* drop empty SYN_REPORT groups */ continue; } else if (head != i) { /* move entry to fill the gap */ client->buffer[head].time = ev->time; client->buffer[head].type = ev->type; client->buffer[head].code = ev->code; client->buffer[head].value = ev->value; } num++; head = (head + 1) & mask; if (is_report) { num = 0; client->packet_head = head; } } client->head = head;} /* queue SYN_DROPPED event */static void evdev_queue_syn_dropped(struct evdev_client *client){ unsigned long flags; struct input_event ev; ktime_t time; time = ktime_get(); if (client->clkid != CLOCK_MONOTONIC) time = ktime_sub(time, ktime_get_monotonic_offset()); ev.time = ktime_to_timeval(time); ev.type = EV_SYN; ev.code = SYN_DROPPED; ev.value = 0; spin_lock_irqsave(&client->buffer_lock, flags); client->buffer[client->head++] = ev; client->head &= client->bufsize - 1; if (unlikely(client->head == client->tail)) { /* drop queue but keep our SYN_DROPPED event */ client->tail = (client->head - 1) & (client->bufsize - 1); client->packet_head = client->tail; } spin_unlock_irqrestore(&client->buffer_lock, flags);} static void __pass_event(struct evdev_client *client, const struct input_event *event){ client->buffer[client->head++] = *event; client->head &= client->bufsize - 1; if (unlikely(client->head == client->tail)) { /* * This effectively "drops" all unconsumed events, leaving * EV_SYN/SYN_DROPPED plus the newest event in the queue. */ client->tail = (client->head - 2) & (client->bufsize - 1); client->buffer[client->tail].time = event->time; client->buffer[client->tail].type = EV_SYN; client->buffer[client->tail].code = SYN_DROPPED; client->buffer[client->tail].value = 0; client->packet_head = client->tail; } if (event->type == EV_SYN && event->code == SYN_REPORT) { client->packet_head = client->head; kill_fasync(&client->fasync, SIGIO, POLL_IN); }} static void evdev_pass_values(struct evdev_client *client, const struct input_value *vals, unsigned int count, ktime_t mono, ktime_t real){ struct evdev *evdev = client->evdev; const struct input_value *v; struct input_event event; bool wakeup = false; event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? mono : real); /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); for (v = vals; v != vals + count; v++) { event.type = v->type; event.code = v->code; event.value = v->value; __pass_event(client, &event); if (v->type == EV_SYN && v->code == SYN_REPORT) wakeup = true; } spin_unlock(&client->buffer_lock); if (wakeup) wake_up_interruptible(&evdev->wait);} /* * Pass incoming events to all connected clients. */static void evdev_events(struct input_handle *handle, const struct input_value *vals, unsigned int count){ struct evdev *evdev = handle->private; struct evdev_client *client; ktime_t time_mono, time_real; time_mono = ktime_get(); time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); rcu_read_lock(); client = rcu_dereference(evdev->grab); if (client) evdev_pass_values(client, vals, count, time_mono, time_real); else list_for_each_entry_rcu(client, &evdev->client_list, node) evdev_pass_values(client, vals, count, time_mono, time_real); rcu_read_unlock();} /* * Pass incoming event to all connected clients. */static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value){ struct input_value vals[] = { { type, code, value } }; evdev_events(handle, vals, 1);} static int evdev_fasync(int fd, struct file *file, int on){ struct evdev_client *client = file->private_data; return fasync_helper(fd, file, on, &client->fasync);} static int evdev_flush(struct file *file, fl_owner_t id){ struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; int retval; retval = mutex_lock_interruptible(&evdev->mutex); if (retval) return retval; if (!evdev->exist) retval = -ENODEV; else retval = input_flush_device(&evdev->handle, file); mutex_unlock(&evdev->mutex); return retval;} static void evdev_free(struct device *dev){ struct evdev *evdev = container_of(dev, struct evdev, dev); input_put_device(evdev->handle.dev); kfree(evdev);} /* * Grabs an event device (along with underlying input device). * This function is called with evdev->mutex taken. */static int evdev_grab(struct evdev *evdev, struct evdev_client *client){ int error; if (evdev->grab) return -EBUSY; error = input_grab_device(&evdev->handle); if (error) return error; rcu_assign_pointer(evdev->grab, client); return 0;} static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client){ struct evdev_client *grab = rcu_dereference_protected(evdev->grab, lockdep_is_held(&evdev->mutex)); if (grab != client) return -EINVAL; rcu_assign_pointer(evdev->grab, NULL); synchronize_rcu(); input_release_device(&evdev->handle); return 0;} static void evdev_attach_client(struct evdev *evdev, struct evdev_client *client){ spin_lock(&evdev->client_lock); list_add_tail_rcu(&client->node, &evdev->client_list); spin_unlock(&evdev->client_lock);} static void evdev_detach_client(struct evdev *evdev, struct evdev_client *client){ spin_lock(&evdev->client_lock); list_del_rcu(&client->node); spin_unlock(&evdev->client_lock); synchronize_rcu();} static int evdev_open_device(struct evdev *evdev){ int retval; retval = mutex_lock_interruptible(&evdev->mutex); if (retval) return retval; if (!evdev->exist) retval = -ENODEV; else if (!evdev->open++) { retval = input_open_device(&evdev->handle); if (retval) evdev->open--; } mutex_unlock(&evdev->mutex); return retval;} static void evdev_close_device(struct evdev *evdev){ mutex_lock(&evdev->mutex); if (evdev->exist && !--evdev->open) input_close_device(&evdev->handle); mutex_unlock(&evdev->mutex);} /* * Wake up users waiting for IO so they can disconnect from * dead device. */static void evdev_hangup(struct evdev *evdev){ struct evdev_client *client; spin_lock(&evdev->client_lock); list_for_each_entry(client, &evdev->client_list, node) kill_fasync(&client->fasync, SIGIO, POLL_HUP); spin_unlock(&evdev->client_lock); wake_up_interruptible(&evdev->wait);} static int evdev_release(struct inode *inode, struct file *file){ struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; mutex_lock(&evdev->mutex); evdev_ungrab(evdev, client); mutex_unlock(&evdev->mutex); evdev_detach_client(evdev, client); kfree(client); evdev_close_device(evdev); return 0;} static unsigned int evdev_compute_buffer_size(struct input_dev *dev){ unsigned int n_events = max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS, EVDEV_MIN_BUFFER_SIZE); return roundup_pow_of_two(n_events);} static int evdev_open(struct inode *inode, struct file *file){ struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev); unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev); struct evdev_client *client; int error; client = kzalloc(sizeof(struct evdev_client) + bufsize * sizeof(struct input_event), GFP_KERNEL); if (!client) return -ENOMEM; client->bufsize = bufsize; spin_lock_init(&client->buffer_lock); client->evdev = evdev; evdev_attach_client(evdev, client); error = evdev_open_device(evdev); if (error) goto err_free_client; file->private_data = client; nonseekable_open(inode, file); return 0; err_free_client: evdev_detach_client(evdev, client); kfree(client); return error;} static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos){ struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; struct input_event event; int retval = 0; if (count != 0 && count < input_event_size()) return -EINVAL; retval = mutex_lock_interruptible(&evdev->mutex); if (retval) return retval; if (!evdev->exist) { retval = -ENODEV; goto out; } while (retval + input_event_size() <= count) { if (input_event_from_user(buffer + retval, &event)) { retval = -EFAULT; goto out; } retval += input_event_size(); input_inject_event(&evdev->handle, event.type, event.code, event.value); } out: mutex_unlock(&evdev->mutex); return retval;} static int evdev_fetch_next_event(struct evdev_client *client, struct input_event *event){ int have_event; spin_lock_irq(&client->buffer_lock); have_event = client->packet_head != client->tail; if (have_event) { *event = client->buffer[client->tail++]; client->tail &= client->bufsize - 1; } spin_unlock_irq(&client->buffer_lock); return have_event;} static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos){ struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; struct input_event event; size_t read = 0; int error; if (count != 0 && count < input_event_size()) return -EINVAL; for (;;) { if (!evdev->exist) return -ENODEV; if (client->packet_head == client->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; /* * count == 0 is special - no IO is done but we check * for error conditions (see above). */ if (count == 0) break; while (read + input_event_size() <= count && evdev_fetch_next_event(client, &event)) {Lines 1–500 of 1193. Load more
/* * Event char devices, giving access to raw input device events. * * Copyright (c) 1999-2002 Vojtech Pavlik * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define EVDEV_MINOR_BASE 64 #define EVDEV_MINORS 32 #define EVDEV_MIN_BUFFER_SIZE 64U #define EVDEV_BUF_PACKETS 8 #include <linux/poll.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/init.h> #include <linux/input/mt.h> #include <linux/major.h> #include <linux/device.h> #include <linux/cdev.h> #include "input-compat.h" struct evdev { int open; struct input_handle handle; wait_queue_head_t wait; struct evdev_client __rcu *grab; struct list_head client_list; spinlock_t client_lock; /* protects client_list */ struct mutex mutex; struct device dev; struct cdev cdev; bool exist; }; struct evdev_client { unsigned int head; unsigned int tail; unsigned int packet_head; /* [future] position of the first element of next packet */ spinlock_t buffer_lock; /* protects access to buffer, head and tail */ struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; int clkid; unsigned int bufsize; struct input_event buffer[]; }; /* flush queued events of type @type, caller must hold client->buffer_lock */ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) { unsigned int i, head, num; unsigned int mask = client->bufsize - 1; bool is_report; struct input_event *ev; BUG_ON(type == EV_SYN); head = client->tail; client->packet_head = client->tail; /* init to 1 so a leading SYN_REPORT will not be dropped */ num = 1; for (i = client->tail; i != client->head; i = (i + 1) & mask) { ev = &client->buffer[i]; is_report = ev->type == EV_SYN && ev->code == SYN_REPORT; if (ev->type == type) { /* drop matched entry */ continue; } else if (is_report && !num) { /* drop empty SYN_REPORT groups */ continue; } else if (head != i) { /* move entry to fill the gap */ client->buffer[head].time = ev->time; client->buffer[head].type = ev->type; client->buffer[head].code = ev->code; client->buffer[head].value = ev->value; } num++; head = (head + 1) & mask; if (is_report) { num = 0; client->packet_head = head; } } client->head = head; } /* queue SYN_DROPPED event */ static void evdev_queue_syn_dropped(struct evdev_client *client) { unsigned long flags; struct input_event ev; ktime_t time; time = ktime_get(); if (client->clkid != CLOCK_MONOTONIC) time = ktime_sub(time, ktime_get_monotonic_offset()); ev.time = ktime_to_timeval(time); ev.type = EV_SYN; ev.code = SYN_DROPPED; ev.value = 0; spin_lock_irqsave(&client->buffer_lock, flags); client->buffer[client->head++] = ev; client->head &= client->bufsize - 1; if (unlikely(client->head == client->tail)) { /* drop queue but keep our SYN_DROPPED event */ client->tail = (client->head - 1) & (client->bufsize - 1); client->packet_head = client->tail; } spin_unlock_irqrestore(&client->buffer_lock, flags); } static void __pass_event(struct evdev_client *client, const struct input_event *event) { client->buffer[client->head++] = *event; client->head &= client->bufsize - 1; if (unlikely(client->head == client->tail)) { /* * This effectively "drops" all unconsumed events, leaving * EV_SYN/SYN_DROPPED plus the newest event in the queue. */ client->tail = (client->head - 2) & (client->bufsize - 1); client->buffer[client->tail].time = event->time; client->buffer[client->tail].type = EV_SYN; client->buffer[client->tail].code = SYN_DROPPED; client->buffer[client->tail].value = 0; client->packet_head = client->tail; } if (event->type == EV_SYN && event->code == SYN_REPORT) { client->packet_head = client->head; kill_fasync(&client->fasync, SIGIO, POLL_IN); } } static void evdev_pass_values(struct evdev_client *client, const struct input_value *vals, unsigned int count, ktime_t mono, ktime_t real) { struct evdev *evdev = client->evdev; const struct input_value *v; struct input_event event; bool wakeup = false; event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? mono : real); /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); for (v = vals; v != vals + count; v++) { event.type = v->type; event.code = v->code; event.value = v->value; __pass_event(client, &event); if (v->type == EV_SYN && v->code == SYN_REPORT) wakeup = true; } spin_unlock(&client->buffer_lock); if (wakeup) wake_up_interruptible(&evdev->wait); } /* * Pass incoming events to all connected clients. */ static void evdev_events(struct input_handle *handle, const struct input_value *vals, unsigned int count) { struct evdev *evdev = handle->private; struct evdev_client *client; ktime_t time_mono, time_real; time_mono = ktime_get(); time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); rcu_read_lock(); client = rcu_dereference(evdev->grab); if (client) evdev_pass_values(client, vals, count, time_mono, time_real); else list_for_each_entry_rcu(client, &evdev->client_list, node) evdev_pass_values(client, vals, count, time_mono, time_real); rcu_read_unlock(); } /* * Pass incoming event to all connected clients. */ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct input_value vals[] = { { type, code, value } }; evdev_events(handle, vals, 1); } static int evdev_fasync(int fd, struct file *file, int on) { struct evdev_client *client = file->private_data; return fasync_helper(fd, file, on, &client->fasync); } static int evdev_flush(struct file *file, fl_owner_t id) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; int retval; retval = mutex_lock_interruptible(&evdev->mutex); if (retval) return retval; if (!evdev->exist) retval = -ENODEV; else retval = input_flush_device(&evdev->handle, file); mutex_unlock(&evdev->mutex); return retval; } static void evdev_free(struct device *dev) { struct evdev *evdev = container_of(dev, struct evdev, dev); input_put_device(evdev->handle.dev); kfree(evdev); } /* * Grabs an event device (along with underlying input device). * This function is called with evdev->mutex taken. */ static int evdev_grab(struct evdev *evdev, struct evdev_client *client) { int error; if (evdev->grab) return -EBUSY; error = input_grab_device(&evdev->handle); if (error) return error; rcu_assign_pointer(evdev->grab, client); return 0; } static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client) { struct evdev_client *grab = rcu_dereference_protected(evdev->grab, lockdep_is_held(&evdev->mutex)); if (grab != client) return -EINVAL; rcu_assign_pointer(evdev->grab, NULL); synchronize_rcu(); input_release_device(&evdev->handle); return 0; } static void evdev_attach_client(struct evdev *evdev, struct evdev_client *client) { spin_lock(&evdev->client_lock); list_add_tail_rcu(&client->node, &evdev->client_list); spin_unlock(&evdev->client_lock); } static void evdev_detach_client(struct evdev *evdev, struct evdev_client *client) { spin_lock(&evdev->client_lock); list_del_rcu(&client->node); spin_unlock(&evdev->client_lock); synchronize_rcu(); } static int evdev_open_device(struct evdev *evdev) { int retval; retval = mutex_lock_interruptible(&evdev->mutex); if (retval) return retval; if (!evdev->exist) retval = -ENODEV; else if (!evdev->open++) { retval = input_open_device(&evdev->handle); if (retval) evdev->open--; } mutex_unlock(&evdev->mutex); return retval; } static void evdev_close_device(struct evdev *evdev) { mutex_lock(&evdev->mutex); if (evdev->exist && !--evdev->open) input_close_device(&evdev->handle); mutex_unlock(&evdev->mutex); } /* * Wake up users waiting for IO so they can disconnect from * dead device. */ static void evdev_hangup(struct evdev *evdev) { struct evdev_client *client; spin_lock(&evdev->client_lock); list_for_each_entry(client, &evdev->client_list, node) kill_fasync(&client->fasync, SIGIO, POLL_HUP); spin_unlock(&evdev->client_lock); wake_up_interruptible(&evdev->wait); } static int evdev_release(struct inode *inode, struct file *file) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; mutex_lock(&evdev->mutex); evdev_ungrab(evdev, client); mutex_unlock(&evdev->mutex); evdev_detach_client(evdev, client); kfree(client); evdev_close_device(evdev); return 0; } static unsigned int evdev_compute_buffer_size(struct input_dev *dev) { unsigned int n_events = max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS, EVDEV_MIN_BUFFER_SIZE); return roundup_pow_of_two(n_events); } static int evdev_open(struct inode *inode, struct file *file) { struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev); unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev); struct evdev_client *client; int error; client = kzalloc(sizeof(struct evdev_client) + bufsize * sizeof(struct input_event), GFP_KERNEL); if (!client) return -ENOMEM; client->bufsize = bufsize; spin_lock_init(&client->buffer_lock); client->evdev = evdev; evdev_attach_client(evdev, client); error = evdev_open_device(evdev); if (error) goto err_free_client; file->private_data = client; nonseekable_open(inode, file); return 0; err_free_client: evdev_detach_client(evdev, client); kfree(client); return error; } static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; struct input_event event; int retval = 0; if (count != 0 && count < input_event_size()) return -EINVAL; retval = mutex_lock_interruptible(&evdev->mutex); if (retval) return retval; if (!evdev->exist) { retval = -ENODEV; goto out; } while (retval + input_event_size() <= count) { if (input_event_from_user(buffer + retval, &event)) { retval = -EFAULT; goto out; } retval += input_event_size(); input_inject_event(&evdev->handle, event.type, event.code, event.value); } out: mutex_unlock(&evdev->mutex); return retval; } static int evdev_fetch_next_event(struct evdev_client *client, struct input_event *event) { int have_event; spin_lock_irq(&client->buffer_lock); have_event = client->packet_head != client->tail; if (have_event) { *event = client->buffer[client->tail++]; client->tail &= client->bufsize - 1; } spin_unlock_irq(&client->buffer_lock); return have_event; } static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; struct input_event event; size_t read = 0; int error; if (count != 0 && count < input_event_size()) return -EINVAL; for (;;) { if (!evdev->exist) return -ENODEV; if (client->packet_head == client->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; /* * count == 0 is special - no IO is done but we check * for error conditions (see above). */ if (count == 0) break; while (read + input_event_size() <= count && evdev_fetch_next_event(client, &event)) {