summaryrefslogtreecommitdiff
path: root/drivers/input/mousedev.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2012-10-08 09:07:24 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-10-08 09:37:55 -0700
commit7f8d4cad1e4e11a45d02bd6e024cc2812963c38a (patch)
treeac592d99a390f1aecf9944e10d05abe4ec0f1b76 /drivers/input/mousedev.c
parent0124be49770469cfb258d7df4693e70b4c5fb013 (diff)
downloadlwn-7f8d4cad1e4e11a45d02bd6e024cc2812963c38a.tar.gz
lwn-7f8d4cad1e4e11a45d02bd6e024cc2812963c38a.zip
Input: extend the number of event (and other) devices
Extend the amount of character devices, such as eventX, mouseX and jsX, from a hard limit of 32 per input handler to about 1024 shared across all handlers. To be compatible with legacy installations input handlers will start creating char devices with minors in their legacy range, however once legacy range is exhausted they will start allocating minors from the dynamic range 256-1024. Reviewed-by: David Herrmann <dh.herrmann@googlemail.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/mousedev.c')
-rw-r--r--drivers/input/mousedev.c132
1 files changed, 62 insertions, 70 deletions
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 88b962aeef13..a1b4c37956b2 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -24,6 +24,7 @@
#include <linux/random.h>
#include <linux/major.h>
#include <linux/device.h>
+#include <linux/cdev.h>
#include <linux/kernel.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
@@ -58,14 +59,15 @@ struct mousedev_hw_data {
struct mousedev {
int open;
- int minor;
struct input_handle handle;
wait_queue_head_t wait;
struct list_head client_list;
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct device dev;
+ struct cdev cdev;
bool exist;
+ bool is_mixdev;
struct list_head mixdev_node;
bool opened_by_mixdev;
@@ -111,10 +113,6 @@ struct mousedev_client {
static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
-static struct input_handler mousedev_handler;
-
-static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
-static DEFINE_MUTEX(mousedev_table_mutex);
static struct mousedev *mousedev_mix;
static LIST_HEAD(mousedev_mix_list);
@@ -430,7 +428,7 @@ static int mousedev_open_device(struct mousedev *mousedev)
if (retval)
return retval;
- if (mousedev->minor == MOUSEDEV_MIX)
+ if (mousedev->is_mixdev)
mixdev_open_devices();
else if (!mousedev->exist)
retval = -ENODEV;
@@ -448,7 +446,7 @@ static void mousedev_close_device(struct mousedev *mousedev)
{
mutex_lock(&mousedev->mutex);
- if (mousedev->minor == MOUSEDEV_MIX)
+ if (mousedev->is_mixdev)
mixdev_close_devices();
else if (mousedev->exist && !--mousedev->open)
input_close_device(&mousedev->handle);
@@ -535,35 +533,17 @@ static int mousedev_open(struct inode *inode, struct file *file)
struct mousedev_client *client;
struct mousedev *mousedev;
int error;
- int i;
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (imajor(inode) == MISC_MAJOR)
- i = MOUSEDEV_MIX;
+ mousedev = mousedev_mix;
else
#endif
- i = iminor(inode) - MOUSEDEV_MINOR_BASE;
-
- if (i >= MOUSEDEV_MINORS)
- return -ENODEV;
-
- error = mutex_lock_interruptible(&mousedev_table_mutex);
- if (error)
- return error;
-
- mousedev = mousedev_table[i];
- if (mousedev)
- get_device(&mousedev->dev);
- mutex_unlock(&mousedev_table_mutex);
-
- if (!mousedev)
- return -ENODEV;
+ mousedev = container_of(inode->i_cdev, struct mousedev, cdev);
client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
- if (!client) {
- error = -ENOMEM;
- goto err_put_mousedev;
- }
+ if (!client)
+ return -ENOMEM;
spin_lock_init(&client->packet_lock);
client->pos_x = xres / 2;
@@ -577,13 +557,13 @@ static int mousedev_open(struct inode *inode, struct file *file)
file->private_data = client;
nonseekable_open(inode, file);
+
+ get_device(&mousedev->dev);
return 0;
err_free_client:
mousedev_detach_client(mousedev, client);
kfree(client);
- err_put_mousedev:
- put_device(&mousedev->dev);
return error;
}
@@ -793,19 +773,6 @@ static const struct file_operations mousedev_fops = {
.llseek = noop_llseek,
};
-static int mousedev_install_chrdev(struct mousedev *mousedev)
-{
- mousedev_table[mousedev->minor] = mousedev;
- return 0;
-}
-
-static void mousedev_remove_chrdev(struct mousedev *mousedev)
-{
- mutex_lock(&mousedev_table_mutex);
- mousedev_table[mousedev->minor] = NULL;
- mutex_unlock(&mousedev_table_mutex);
-}
-
/*
* Mark device non-existent. This disables writes, ioctls and
* prevents new users from opening the device. Already posted
@@ -840,24 +807,50 @@ static void mousedev_cleanup(struct mousedev *mousedev)
mousedev_mark_dead(mousedev);
mousedev_hangup(mousedev);
- mousedev_remove_chrdev(mousedev);
+
+ cdev_del(&mousedev->cdev);
/* mousedev is marked dead so no one else accesses mousedev->open */
if (mousedev->open)
input_close_device(handle);
}
+static int mousedev_reserve_minor(bool mixdev)
+{
+ int minor;
+
+ if (mixdev) {
+ minor = input_get_new_minor(MOUSEDEV_MIX, 1, false);
+ if (minor < 0)
+ pr_err("failed to reserve mixdev minor: %d\n", minor);
+ } else {
+ minor = input_get_new_minor(MOUSEDEV_MINOR_BASE,
+ MOUSEDEV_MINORS, true);
+ if (minor < 0)
+ pr_err("failed to reserve new minor: %d\n", minor);
+ }
+
+ return minor;
+}
+
static struct mousedev *mousedev_create(struct input_dev *dev,
struct input_handler *handler,
- int minor)
+ bool mixdev)
{
struct mousedev *mousedev;
+ int minor;
int error;
+ minor = mousedev_reserve_minor(mixdev);
+ if (minor < 0) {
+ error = minor;
+ goto err_out;
+ }
+
mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
if (!mousedev) {
error = -ENOMEM;
- goto err_out;
+ goto err_free_minor;
}
INIT_LIST_HEAD(&mousedev->client_list);
@@ -865,16 +858,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
spin_lock_init(&mousedev->client_lock);
mutex_init(&mousedev->mutex);
lockdep_set_subclass(&mousedev->mutex,
- minor == MOUSEDEV_MIX ? SINGLE_DEPTH_NESTING : 0);
+ mixdev ? SINGLE_DEPTH_NESTING : 0);
init_waitqueue_head(&mousedev->wait);
- if (minor == MOUSEDEV_MIX)
+ if (mixdev) {
dev_set_name(&mousedev->dev, "mice");
- else
- dev_set_name(&mousedev->dev, "mouse%d", minor);
+ } else {
+ int dev_no = minor;
+ /* Normalize device number if it falls into legacy range */
+ if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS)
+ dev_no -= MOUSEDEV_MINOR_BASE;
+ dev_set_name(&mousedev->dev, "mouse%d", dev_no);
+ }
- mousedev->minor = minor;
mousedev->exist = true;
+ mousedev->is_mixdev = mixdev;
mousedev->handle.dev = input_get_device(dev);
mousedev->handle.name = dev_name(&mousedev->dev);
mousedev->handle.handler = handler;
@@ -883,17 +881,18 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
mousedev->dev.class = &input_class;
if (dev)
mousedev->dev.parent = &dev->dev;
- mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor);
+ mousedev->dev.devt = MKDEV(INPUT_MAJOR, minor);
mousedev->dev.release = mousedev_free;
device_initialize(&mousedev->dev);
- if (minor != MOUSEDEV_MIX) {
+ if (!mixdev) {
error = input_register_handle(&mousedev->handle);
if (error)
goto err_free_mousedev;
}
- error = mousedev_install_chrdev(mousedev);
+ cdev_init(&mousedev->cdev, &mousedev_fops);
+ error = cdev_add(&mousedev->cdev, mousedev->dev.devt, 1);
if (error)
goto err_unregister_handle;
@@ -906,10 +905,12 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
err_cleanup_mousedev:
mousedev_cleanup(mousedev);
err_unregister_handle:
- if (minor != MOUSEDEV_MIX)
+ if (!mixdev)
input_unregister_handle(&mousedev->handle);
err_free_mousedev:
put_device(&mousedev->dev);
+ err_free_minor:
+ input_free_minor(minor);
err_out:
return ERR_PTR(error);
}
@@ -918,7 +919,8 @@ static void mousedev_destroy(struct mousedev *mousedev)
{
device_del(&mousedev->dev);
mousedev_cleanup(mousedev);
- if (mousedev->minor != MOUSEDEV_MIX)
+ input_free_minor(MINOR(mousedev->dev.devt));
+ if (!mousedev->is_mixdev)
input_unregister_handle(&mousedev->handle);
put_device(&mousedev->dev);
}
@@ -967,19 +969,9 @@ static int mousedev_connect(struct input_handler *handler,
const struct input_device_id *id)
{
struct mousedev *mousedev;
- int minor;
int error;
- for (minor = 0; minor < MOUSEDEV_MINORS; minor++)
- if (!mousedev_table[minor])
- break;
-
- if (minor == MOUSEDEV_MINORS) {
- pr_err("no more free mousedev devices\n");
- return -ENFILE;
- }
-
- mousedev = mousedev_create(dev, handler, minor);
+ mousedev = mousedev_create(dev, handler, false);
if (IS_ERR(mousedev))
return PTR_ERR(mousedev);
@@ -1055,7 +1047,7 @@ static struct input_handler mousedev_handler = {
.event = mousedev_event,
.connect = mousedev_connect,
.disconnect = mousedev_disconnect,
- .fops = &mousedev_fops,
+ .legacy_minors = true,
.minor = MOUSEDEV_MINOR_BASE,
.name = "mousedev",
.id_table = mousedev_ids,
@@ -1098,7 +1090,7 @@ static int __init mousedev_init(void)
{
int error;
- mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX);
+ mousedev_mix = mousedev_create(NULL, &mousedev_handler, true);
if (IS_ERR(mousedev_mix))
return PTR_ERR(mousedev_mix);