summaryrefslogtreecommitdiffstats
path: root/drivers/input/mousedev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/mousedev.c')
-rw-r--r--drivers/input/mousedev.c225
1 files changed, 115 insertions, 110 deletions
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 0110b5a3a16..a1b4c37956b 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -24,10 +24,8 @@
#include <linux/random.h>
#include <linux/major.h>
#include <linux/device.h>
+#include <linux/cdev.h>
#include <linux/kernel.h>
-#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
-#include <linux/miscdevice.h>
-#endif
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces");
@@ -61,17 +59,18 @@ 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;
- int mixdev_open;
+ bool opened_by_mixdev;
struct mousedev_hw_data packet;
unsigned int pkt_count;
@@ -114,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);
@@ -433,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;
@@ -451,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);
@@ -472,11 +467,11 @@ static void mixdev_open_devices(void)
return;
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
- if (!mousedev->mixdev_open) {
+ if (!mousedev->opened_by_mixdev) {
if (mousedev_open_device(mousedev))
continue;
- mousedev->mixdev_open = 1;
+ mousedev->opened_by_mixdev = true;
}
}
}
@@ -494,8 +489,8 @@ static void mixdev_close_devices(void)
return;
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
- if (mousedev->mixdev_open) {
- mousedev->mixdev_open = 0;
+ if (mousedev->opened_by_mixdev) {
+ mousedev->opened_by_mixdev = false;
mousedev_close_device(mousedev);
}
}
@@ -538,36 +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;
@@ -580,13 +556,14 @@ static int mousedev_open(struct inode *inode, struct file *file)
goto err_free_client;
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;
}
@@ -786,29 +763,16 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait)
}
static const struct file_operations mousedev_fops = {
- .owner = THIS_MODULE,
- .read = mousedev_read,
- .write = mousedev_write,
- .poll = mousedev_poll,
- .open = mousedev_open,
- .release = mousedev_release,
- .fasync = mousedev_fasync,
- .llseek = noop_llseek,
+ .owner = THIS_MODULE,
+ .read = mousedev_read,
+ .write = mousedev_write,
+ .poll = mousedev_poll,
+ .open = mousedev_open,
+ .release = mousedev_release,
+ .fasync = mousedev_fasync,
+ .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
@@ -843,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);
@@ -868,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;
@@ -886,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;
@@ -909,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);
}
@@ -921,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);
}
@@ -939,7 +938,7 @@ static int mixdev_add_device(struct mousedev *mousedev)
if (retval)
goto out;
- mousedev->mixdev_open = 1;
+ mousedev->opened_by_mixdev = true;
}
get_device(&mousedev->dev);
@@ -954,8 +953,8 @@ static void mixdev_remove_device(struct mousedev *mousedev)
{
mutex_lock(&mousedev_mix->mutex);
- if (mousedev->mixdev_open) {
- mousedev->mixdev_open = 0;
+ if (mousedev->opened_by_mixdev) {
+ mousedev->opened_by_mixdev = false;
mousedev_close_device(mousedev);
}
@@ -970,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,27 +1044,53 @@ static const struct input_device_id mousedev_ids[] = {
MODULE_DEVICE_TABLE(input, mousedev_ids);
static struct input_handler mousedev_handler = {
- .event = mousedev_event,
- .connect = mousedev_connect,
- .disconnect = mousedev_disconnect,
- .fops = &mousedev_fops,
- .minor = MOUSEDEV_MINOR_BASE,
- .name = "mousedev",
- .id_table = mousedev_ids,
+ .event = mousedev_event,
+ .connect = mousedev_connect,
+ .disconnect = mousedev_disconnect,
+ .legacy_minors = true,
+ .minor = MOUSEDEV_MINOR_BASE,
+ .name = "mousedev",
+ .id_table = mousedev_ids,
};
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
+#include <linux/miscdevice.h>
+
static struct miscdevice psaux_mouse = {
- PSMOUSE_MINOR, "psaux", &mousedev_fops
+ .minor = PSMOUSE_MINOR,
+ .name = "psaux",
+ .fops = &mousedev_fops,
};
-static int psaux_registered;
+
+static bool psaux_registered;
+
+static void __init mousedev_psaux_register(void)
+{
+ int error;
+
+ error = misc_register(&psaux_mouse);
+ if (error)
+ pr_warn("could not register psaux device, error: %d\n",
+ error);
+ else
+ psaux_registered = true;
+}
+
+static void __exit mousedev_psaux_unregister(void)
+{
+ if (psaux_registered)
+ misc_deregister(&psaux_mouse);
+}
+#else
+static inline void mousedev_psaux_register(void) { }
+static inline void mousedev_psaux_unregister(void) { }
#endif
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);
@@ -1085,14 +1100,7 @@ static int __init mousedev_init(void)
return error;
}
-#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
- error = misc_register(&psaux_mouse);
- if (error)
- pr_warning("could not register psaux device, error: %d\n",
- error);
- else
- psaux_registered = 1;
-#endif
+ mousedev_psaux_register();
pr_info("PS/2 mouse device common for all mice\n");
@@ -1101,10 +1109,7 @@ static int __init mousedev_init(void)
static void __exit mousedev_exit(void)
{
-#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
- if (psaux_registered)
- misc_deregister(&psaux_mouse);
-#endif
+ mousedev_psaux_unregister();
input_unregister_handler(&mousedev_handler);
mousedev_destroy(mousedev_mix);
}