|
@@ -24,6 +24,7 @@
|
|
#include <linux/random.h>
|
|
#include <linux/random.h>
|
|
#include <linux/major.h>
|
|
#include <linux/major.h>
|
|
#include <linux/device.h>
|
|
#include <linux/device.h>
|
|
|
|
+#include <linux/cdev.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kernel.h>
|
|
|
|
|
|
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
|
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
|
@@ -58,14 +59,15 @@ struct mousedev_hw_data {
|
|
|
|
|
|
struct mousedev {
|
|
struct mousedev {
|
|
int open;
|
|
int open;
|
|
- int minor;
|
|
|
|
struct input_handle handle;
|
|
struct input_handle handle;
|
|
wait_queue_head_t wait;
|
|
wait_queue_head_t wait;
|
|
struct list_head client_list;
|
|
struct list_head client_list;
|
|
spinlock_t client_lock; /* protects client_list */
|
|
spinlock_t client_lock; /* protects client_list */
|
|
struct mutex mutex;
|
|
struct mutex mutex;
|
|
struct device dev;
|
|
struct device dev;
|
|
|
|
+ struct cdev cdev;
|
|
bool exist;
|
|
bool exist;
|
|
|
|
+ bool is_mixdev;
|
|
|
|
|
|
struct list_head mixdev_node;
|
|
struct list_head mixdev_node;
|
|
bool opened_by_mixdev;
|
|
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_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
|
|
static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 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 struct mousedev *mousedev_mix;
|
|
static LIST_HEAD(mousedev_mix_list);
|
|
static LIST_HEAD(mousedev_mix_list);
|
|
|
|
|
|
@@ -430,7 +428,7 @@ static int mousedev_open_device(struct mousedev *mousedev)
|
|
if (retval)
|
|
if (retval)
|
|
return retval;
|
|
return retval;
|
|
|
|
|
|
- if (mousedev->minor == MOUSEDEV_MIX)
|
|
|
|
|
|
+ if (mousedev->is_mixdev)
|
|
mixdev_open_devices();
|
|
mixdev_open_devices();
|
|
else if (!mousedev->exist)
|
|
else if (!mousedev->exist)
|
|
retval = -ENODEV;
|
|
retval = -ENODEV;
|
|
@@ -448,7 +446,7 @@ static void mousedev_close_device(struct mousedev *mousedev)
|
|
{
|
|
{
|
|
mutex_lock(&mousedev->mutex);
|
|
mutex_lock(&mousedev->mutex);
|
|
|
|
|
|
- if (mousedev->minor == MOUSEDEV_MIX)
|
|
|
|
|
|
+ if (mousedev->is_mixdev)
|
|
mixdev_close_devices();
|
|
mixdev_close_devices();
|
|
else if (mousedev->exist && !--mousedev->open)
|
|
else if (mousedev->exist && !--mousedev->open)
|
|
input_close_device(&mousedev->handle);
|
|
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_client *client;
|
|
struct mousedev *mousedev;
|
|
struct mousedev *mousedev;
|
|
int error;
|
|
int error;
|
|
- int i;
|
|
|
|
|
|
|
|
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
|
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
|
if (imajor(inode) == MISC_MAJOR)
|
|
if (imajor(inode) == MISC_MAJOR)
|
|
- i = MOUSEDEV_MIX;
|
|
|
|
|
|
+ mousedev = mousedev_mix;
|
|
else
|
|
else
|
|
#endif
|
|
#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);
|
|
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);
|
|
spin_lock_init(&client->packet_lock);
|
|
client->pos_x = xres / 2;
|
|
client->pos_x = xres / 2;
|
|
@@ -577,13 +557,13 @@ static int mousedev_open(struct inode *inode, struct file *file)
|
|
|
|
|
|
file->private_data = client;
|
|
file->private_data = client;
|
|
nonseekable_open(inode, file);
|
|
nonseekable_open(inode, file);
|
|
|
|
+
|
|
|
|
+ get_device(&mousedev->dev);
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
err_free_client:
|
|
err_free_client:
|
|
mousedev_detach_client(mousedev, client);
|
|
mousedev_detach_client(mousedev, client);
|
|
kfree(client);
|
|
kfree(client);
|
|
- err_put_mousedev:
|
|
|
|
- put_device(&mousedev->dev);
|
|
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -793,19 +773,6 @@ static const struct file_operations mousedev_fops = {
|
|
.llseek = noop_llseek,
|
|
.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
|
|
* Mark device non-existent. This disables writes, ioctls and
|
|
* prevents new users from opening the device. Already posted
|
|
* 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_mark_dead(mousedev);
|
|
mousedev_hangup(mousedev);
|
|
mousedev_hangup(mousedev);
|
|
- mousedev_remove_chrdev(mousedev);
|
|
|
|
|
|
+
|
|
|
|
+ cdev_del(&mousedev->cdev);
|
|
|
|
|
|
/* mousedev is marked dead so no one else accesses mousedev->open */
|
|
/* mousedev is marked dead so no one else accesses mousedev->open */
|
|
if (mousedev->open)
|
|
if (mousedev->open)
|
|
input_close_device(handle);
|
|
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,
|
|
static struct mousedev *mousedev_create(struct input_dev *dev,
|
|
struct input_handler *handler,
|
|
struct input_handler *handler,
|
|
- int minor)
|
|
|
|
|
|
+ bool mixdev)
|
|
{
|
|
{
|
|
struct mousedev *mousedev;
|
|
struct mousedev *mousedev;
|
|
|
|
+ int minor;
|
|
int error;
|
|
int error;
|
|
|
|
|
|
|
|
+ minor = mousedev_reserve_minor(mixdev);
|
|
|
|
+ if (minor < 0) {
|
|
|
|
+ error = minor;
|
|
|
|
+ goto err_out;
|
|
|
|
+ }
|
|
|
|
+
|
|
mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
|
|
mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
|
|
if (!mousedev) {
|
|
if (!mousedev) {
|
|
error = -ENOMEM;
|
|
error = -ENOMEM;
|
|
- goto err_out;
|
|
|
|
|
|
+ goto err_free_minor;
|
|
}
|
|
}
|
|
|
|
|
|
INIT_LIST_HEAD(&mousedev->client_list);
|
|
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);
|
|
spin_lock_init(&mousedev->client_lock);
|
|
mutex_init(&mousedev->mutex);
|
|
mutex_init(&mousedev->mutex);
|
|
lockdep_set_subclass(&mousedev->mutex,
|
|
lockdep_set_subclass(&mousedev->mutex,
|
|
- minor == MOUSEDEV_MIX ? SINGLE_DEPTH_NESTING : 0);
|
|
|
|
|
|
+ mixdev ? SINGLE_DEPTH_NESTING : 0);
|
|
init_waitqueue_head(&mousedev->wait);
|
|
init_waitqueue_head(&mousedev->wait);
|
|
|
|
|
|
- if (minor == MOUSEDEV_MIX)
|
|
|
|
|
|
+ if (mixdev) {
|
|
dev_set_name(&mousedev->dev, "mice");
|
|
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->exist = true;
|
|
|
|
+ mousedev->is_mixdev = mixdev;
|
|
mousedev->handle.dev = input_get_device(dev);
|
|
mousedev->handle.dev = input_get_device(dev);
|
|
mousedev->handle.name = dev_name(&mousedev->dev);
|
|
mousedev->handle.name = dev_name(&mousedev->dev);
|
|
mousedev->handle.handler = handler;
|
|
mousedev->handle.handler = handler;
|
|
@@ -883,17 +881,18 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
|
|
mousedev->dev.class = &input_class;
|
|
mousedev->dev.class = &input_class;
|
|
if (dev)
|
|
if (dev)
|
|
mousedev->dev.parent = &dev->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;
|
|
mousedev->dev.release = mousedev_free;
|
|
device_initialize(&mousedev->dev);
|
|
device_initialize(&mousedev->dev);
|
|
|
|
|
|
- if (minor != MOUSEDEV_MIX) {
|
|
|
|
|
|
+ if (!mixdev) {
|
|
error = input_register_handle(&mousedev->handle);
|
|
error = input_register_handle(&mousedev->handle);
|
|
if (error)
|
|
if (error)
|
|
goto err_free_mousedev;
|
|
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)
|
|
if (error)
|
|
goto err_unregister_handle;
|
|
goto err_unregister_handle;
|
|
|
|
|
|
@@ -906,10 +905,12 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
|
|
err_cleanup_mousedev:
|
|
err_cleanup_mousedev:
|
|
mousedev_cleanup(mousedev);
|
|
mousedev_cleanup(mousedev);
|
|
err_unregister_handle:
|
|
err_unregister_handle:
|
|
- if (minor != MOUSEDEV_MIX)
|
|
|
|
|
|
+ if (!mixdev)
|
|
input_unregister_handle(&mousedev->handle);
|
|
input_unregister_handle(&mousedev->handle);
|
|
err_free_mousedev:
|
|
err_free_mousedev:
|
|
put_device(&mousedev->dev);
|
|
put_device(&mousedev->dev);
|
|
|
|
+ err_free_minor:
|
|
|
|
+ input_free_minor(minor);
|
|
err_out:
|
|
err_out:
|
|
return ERR_PTR(error);
|
|
return ERR_PTR(error);
|
|
}
|
|
}
|
|
@@ -918,7 +919,8 @@ static void mousedev_destroy(struct mousedev *mousedev)
|
|
{
|
|
{
|
|
device_del(&mousedev->dev);
|
|
device_del(&mousedev->dev);
|
|
mousedev_cleanup(mousedev);
|
|
mousedev_cleanup(mousedev);
|
|
- if (mousedev->minor != MOUSEDEV_MIX)
|
|
|
|
|
|
+ input_free_minor(MINOR(mousedev->dev.devt));
|
|
|
|
+ if (!mousedev->is_mixdev)
|
|
input_unregister_handle(&mousedev->handle);
|
|
input_unregister_handle(&mousedev->handle);
|
|
put_device(&mousedev->dev);
|
|
put_device(&mousedev->dev);
|
|
}
|
|
}
|
|
@@ -967,19 +969,9 @@ static int mousedev_connect(struct input_handler *handler,
|
|
const struct input_device_id *id)
|
|
const struct input_device_id *id)
|
|
{
|
|
{
|
|
struct mousedev *mousedev;
|
|
struct mousedev *mousedev;
|
|
- int minor;
|
|
|
|
int error;
|
|
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))
|
|
if (IS_ERR(mousedev))
|
|
return PTR_ERR(mousedev);
|
|
return PTR_ERR(mousedev);
|
|
|
|
|
|
@@ -1055,7 +1047,7 @@ static struct input_handler mousedev_handler = {
|
|
.event = mousedev_event,
|
|
.event = mousedev_event,
|
|
.connect = mousedev_connect,
|
|
.connect = mousedev_connect,
|
|
.disconnect = mousedev_disconnect,
|
|
.disconnect = mousedev_disconnect,
|
|
- .fops = &mousedev_fops,
|
|
|
|
|
|
+ .legacy_minors = true,
|
|
.minor = MOUSEDEV_MINOR_BASE,
|
|
.minor = MOUSEDEV_MINOR_BASE,
|
|
.name = "mousedev",
|
|
.name = "mousedev",
|
|
.id_table = mousedev_ids,
|
|
.id_table = mousedev_ids,
|
|
@@ -1098,7 +1090,7 @@ static int __init mousedev_init(void)
|
|
{
|
|
{
|
|
int error;
|
|
int error;
|
|
|
|
|
|
- mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX);
|
|
|
|
|
|
+ mousedev_mix = mousedev_create(NULL, &mousedev_handler, true);
|
|
if (IS_ERR(mousedev_mix))
|
|
if (IS_ERR(mousedev_mix))
|
|
return PTR_ERR(mousedev_mix);
|
|
return PTR_ERR(mousedev_mix);
|
|
|
|
|