Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 334093
b: refs/heads/master
c: 7f8d4ca
h: refs/heads/master
i:
  334091: ee0eca2
v: v3
  • Loading branch information
Dmitry Torokhov committed Oct 8, 2012
1 parent f310c0c commit 86f9275
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 257 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0124be49770469cfb258d7df4693e70b4c5fb013
refs/heads/master: 7f8d4cad1e4e11a45d02bd6e024cc2812963c38a
99 changes: 33 additions & 66 deletions trunk/drivers/input/evdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,19 @@
#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;
int minor;
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;
};

Expand All @@ -51,9 +52,6 @@ struct evdev_client {
struct input_event buffer[];
};

static struct evdev *evdev_table[EVDEV_MINORS];
static DEFINE_MUTEX(evdev_table_mutex);

static void __pass_event(struct evdev_client *client,
const struct input_event *event)
{
Expand Down Expand Up @@ -310,35 +308,16 @@ static unsigned int evdev_compute_buffer_size(struct input_dev *dev)

static int evdev_open(struct inode *inode, struct file *file)
{
struct evdev *evdev;
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 i = iminor(inode) - EVDEV_MINOR_BASE;
unsigned int bufsize;
int error;

if (i >= EVDEV_MINORS)
return -ENODEV;

error = mutex_lock_interruptible(&evdev_table_mutex);
if (error)
return error;
evdev = evdev_table[i];
if (evdev)
get_device(&evdev->dev);
mutex_unlock(&evdev_table_mutex);

if (!evdev)
return -ENODEV;

bufsize = evdev_compute_buffer_size(evdev->handle.dev);

client = kzalloc(sizeof(struct evdev_client) +
bufsize * sizeof(struct input_event),
GFP_KERNEL);
if (!client) {
error = -ENOMEM;
goto err_put_evdev;
}
if (!client)
return -ENOMEM;

client->bufsize = bufsize;
spin_lock_init(&client->buffer_lock);
Expand All @@ -352,13 +331,12 @@ static int evdev_open(struct inode *inode, struct file *file)
file->private_data = client;
nonseekable_open(inode, file);

get_device(&evdev->dev);
return 0;

err_free_client:
evdev_detach_client(evdev, client);
kfree(client);
err_put_evdev:
put_device(&evdev->dev);
return error;
}

Expand Down Expand Up @@ -942,26 +920,6 @@ static const struct file_operations evdev_fops = {
.llseek = no_llseek,
};

static int evdev_install_chrdev(struct evdev *evdev)
{
/*
* No need to do any locking here as calls to connect and
* disconnect are serialized by the input core
*/
evdev_table[evdev->minor] = evdev;
return 0;
}

static void evdev_remove_chrdev(struct evdev *evdev)
{
/*
* Lock evdev table to prevent race with evdev_open()
*/
mutex_lock(&evdev_table_mutex);
evdev_table[evdev->minor] = NULL;
mutex_unlock(&evdev_table_mutex);
}

/*
* Mark device non-existent. This disables writes, ioctls and
* prevents new users from opening the device. Already posted
Expand All @@ -980,7 +938,8 @@ static void evdev_cleanup(struct evdev *evdev)

evdev_mark_dead(evdev);
evdev_hangup(evdev);
evdev_remove_chrdev(evdev);

cdev_del(&evdev->cdev);

/* evdev is marked dead so no one else accesses evdev->open */
if (evdev->open) {
Expand All @@ -991,43 +950,47 @@ static void evdev_cleanup(struct evdev *evdev)

/*
* Create new evdev device. Note that input core serializes calls
* to connect and disconnect so we don't need to lock evdev_table here.
* to connect and disconnect.
*/
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct evdev *evdev;
int minor;
int dev_no;
int error;

for (minor = 0; minor < EVDEV_MINORS; minor++)
if (!evdev_table[minor])
break;

if (minor == EVDEV_MINORS) {
pr_err("no more free evdev devices\n");
return -ENFILE;
minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
if (minor < 0) {
error = minor;
pr_err("failed to reserve new minor: %d\n", error);
return error;
}

evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
if (!evdev)
return -ENOMEM;
if (!evdev) {
error = -ENOMEM;
goto err_free_minor;
}

INIT_LIST_HEAD(&evdev->client_list);
spin_lock_init(&evdev->client_lock);
mutex_init(&evdev->mutex);
init_waitqueue_head(&evdev->wait);

dev_set_name(&evdev->dev, "event%d", minor);
evdev->exist = true;
evdev->minor = minor;

dev_no = minor;
/* Normalize device number if it falls into legacy range */
if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS)
dev_no -= EVDEV_MINOR_BASE;
dev_set_name(&evdev->dev, "event%d", dev_no);

evdev->handle.dev = input_get_device(dev);
evdev->handle.name = dev_name(&evdev->dev);
evdev->handle.handler = handler;
evdev->handle.private = evdev;

evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
evdev->dev.release = evdev_free;
Expand All @@ -1037,7 +1000,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
if (error)
goto err_free_evdev;

error = evdev_install_chrdev(evdev);
cdev_init(&evdev->cdev, &evdev_fops);
error = cdev_add(&evdev->cdev, evdev->dev.devt, 1);
if (error)
goto err_unregister_handle;

Expand All @@ -1053,6 +1017,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
input_unregister_handle(&evdev->handle);
err_free_evdev:
put_device(&evdev->dev);
err_free_minor:
input_free_minor(minor);
return error;
}

Expand All @@ -1062,6 +1028,7 @@ static void evdev_disconnect(struct input_handle *handle)

device_del(&evdev->dev);
evdev_cleanup(evdev);
input_free_minor(MINOR(evdev->dev.devt));
input_unregister_handle(handle);
put_device(&evdev->dev);
}
Expand All @@ -1078,7 +1045,7 @@ static struct input_handler evdev_handler = {
.events = evdev_events,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.legacy_minors = true,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
Expand Down
Loading

0 comments on commit 86f9275

Please sign in to comment.