|
@@ -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,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;
|
|
@@ -579,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;
|
|
|
}
|
|
|
|
|
@@ -785,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
|
|
@@ -842,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);
|
|
@@ -867,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;
|
|
@@ -885,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;
|
|
|
|
|
@@ -908,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);
|
|
|
}
|
|
@@ -920,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);
|
|
|
}
|
|
@@ -938,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);
|
|
@@ -953,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);
|
|
|
}
|
|
|
|
|
@@ -969,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);
|
|
|
|
|
@@ -1054,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);
|
|
|
|
|
@@ -1084,14 +1100,7 @@ static int __init mousedev_init(void)
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
|
|
- error = misc_register(&psaux_mouse);
|
|
|
- if (error)
|
|
|
- pr_warn("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");
|
|
|
|
|
@@ -1100,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);
|
|
|
}
|