]> Pileus Git - ~andy/linux/blobdiff - drivers/input/mousedev.c
Input: extend the number of event (and other) devices
[~andy/linux] / drivers / input / mousedev.c
index 0110b5a3a1678a7a0843672b8505e6f42c664fc1..a1b4c37956b2ef3af055e5c66ccd7753225cabeb 100644 (file)
 #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);
 }