summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/evdev.c99
-rw-r--r--drivers/input/input.c114
-rw-r--r--drivers/input/joydev.c88
-rw-r--r--drivers/input/keyboard/samsung-keypad.c11
-rw-r--r--drivers/input/mousedev.c224
-rw-r--r--drivers/input/tablet/wacom_sys.c145
-rw-r--r--drivers/input/tablet/wacom_wac.c30
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c6
8 files changed, 375 insertions, 342 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 118d0300f1fb..6ae2ac47c9c8 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -23,11 +23,11 @@
#include <linux/input/mt.h>
#include <linux/major.h>
#include <linux/device.h>
+#include <linux/cdev.h>
#include "input-compat.h"
struct evdev {
int open;
- int minor;
struct input_handle handle;
wait_queue_head_t wait;
struct evdev_client __rcu *grab;
@@ -35,6 +35,7 @@ struct evdev {
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct device dev;
+ struct cdev cdev;
bool exist;
};
@@ -51,9 +52,6 @@ struct evdev_client {
struct input_event buffer[];
};
-static struct evdev *evdev_table[EVDEV_MINORS];
-static DEFINE_MUTEX(evdev_table_mutex);
-
static void __pass_event(struct evdev_client *client,
const struct input_event *event)
{
@@ -310,35 +308,16 @@ static unsigned int evdev_compute_buffer_size(struct input_dev *dev)
static int evdev_open(struct inode *inode, struct file *file)
{
- struct evdev *evdev;
+ struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
+ unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);
struct evdev_client *client;
- int i = iminor(inode) - EVDEV_MINOR_BASE;
- unsigned int bufsize;
int error;
- if (i >= EVDEV_MINORS)
- return -ENODEV;
-
- error = mutex_lock_interruptible(&evdev_table_mutex);
- if (error)
- return error;
- evdev = evdev_table[i];
- if (evdev)
- get_device(&evdev->dev);
- mutex_unlock(&evdev_table_mutex);
-
- if (!evdev)
- return -ENODEV;
-
- bufsize = evdev_compute_buffer_size(evdev->handle.dev);
-
client = kzalloc(sizeof(struct evdev_client) +
bufsize * sizeof(struct input_event),
GFP_KERNEL);
- if (!client) {
- error = -ENOMEM;
- goto err_put_evdev;
- }
+ if (!client)
+ return -ENOMEM;
client->bufsize = bufsize;
spin_lock_init(&client->buffer_lock);
@@ -352,13 +331,12 @@ static int evdev_open(struct inode *inode, struct file *file)
file->private_data = client;
nonseekable_open(inode, file);
+ get_device(&evdev->dev);
return 0;
err_free_client:
evdev_detach_client(evdev, client);
kfree(client);
- err_put_evdev:
- put_device(&evdev->dev);
return error;
}
@@ -942,26 +920,6 @@ static const struct file_operations evdev_fops = {
.llseek = no_llseek,
};
-static int evdev_install_chrdev(struct evdev *evdev)
-{
- /*
- * No need to do any locking here as calls to connect and
- * disconnect are serialized by the input core
- */
- evdev_table[evdev->minor] = evdev;
- return 0;
-}
-
-static void evdev_remove_chrdev(struct evdev *evdev)
-{
- /*
- * Lock evdev table to prevent race with evdev_open()
- */
- mutex_lock(&evdev_table_mutex);
- evdev_table[evdev->minor] = NULL;
- mutex_unlock(&evdev_table_mutex);
-}
-
/*
* Mark device non-existent. This disables writes, ioctls and
* prevents new users from opening the device. Already posted
@@ -980,7 +938,8 @@ static void evdev_cleanup(struct evdev *evdev)
evdev_mark_dead(evdev);
evdev_hangup(evdev);
- evdev_remove_chrdev(evdev);
+
+ cdev_del(&evdev->cdev);
/* evdev is marked dead so no one else accesses evdev->open */
if (evdev->open) {
@@ -991,43 +950,47 @@ static void evdev_cleanup(struct evdev *evdev)
/*
* Create new evdev device. Note that input core serializes calls
- * to connect and disconnect so we don't need to lock evdev_table here.
+ * to connect and disconnect.
*/
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct evdev *evdev;
int minor;
+ int dev_no;
int error;
- for (minor = 0; minor < EVDEV_MINORS; minor++)
- if (!evdev_table[minor])
- break;
-
- if (minor == EVDEV_MINORS) {
- pr_err("no more free evdev devices\n");
- return -ENFILE;
+ minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
+ if (minor < 0) {
+ error = minor;
+ pr_err("failed to reserve new minor: %d\n", error);
+ return error;
}
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
- if (!evdev)
- return -ENOMEM;
+ if (!evdev) {
+ error = -ENOMEM;
+ goto err_free_minor;
+ }
INIT_LIST_HEAD(&evdev->client_list);
spin_lock_init(&evdev->client_lock);
mutex_init(&evdev->mutex);
init_waitqueue_head(&evdev->wait);
-
- dev_set_name(&evdev->dev, "event%d", minor);
evdev->exist = true;
- evdev->minor = minor;
+
+ dev_no = minor;
+ /* Normalize device number if it falls into legacy range */
+ if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS)
+ dev_no -= EVDEV_MINOR_BASE;
+ dev_set_name(&evdev->dev, "event%d", dev_no);
evdev->handle.dev = input_get_device(dev);
evdev->handle.name = dev_name(&evdev->dev);
evdev->handle.handler = handler;
evdev->handle.private = evdev;
- evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
+ evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
evdev->dev.release = evdev_free;
@@ -1037,7 +1000,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
if (error)
goto err_free_evdev;
- error = evdev_install_chrdev(evdev);
+ cdev_init(&evdev->cdev, &evdev_fops);
+ error = cdev_add(&evdev->cdev, evdev->dev.devt, 1);
if (error)
goto err_unregister_handle;
@@ -1053,6 +1017,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
input_unregister_handle(&evdev->handle);
err_free_evdev:
put_device(&evdev->dev);
+ err_free_minor:
+ input_free_minor(minor);
return error;
}
@@ -1062,6 +1028,7 @@ static void evdev_disconnect(struct input_handle *handle)
device_del(&evdev->dev);
evdev_cleanup(evdev);
+ input_free_minor(MINOR(evdev->dev.devt));
input_unregister_handle(handle);
put_device(&evdev->dev);
}
@@ -1078,7 +1045,7 @@ static struct input_handler evdev_handler = {
.events = evdev_events,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
- .fops = &evdev_fops,
+ .legacy_minors = true,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
diff --git a/drivers/input/input.c b/drivers/input/input.c
index ace3f7c4226d..53a0ddee7872 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/types.h>
+#include <linux/idr.h>
#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -32,7 +33,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input core");
MODULE_LICENSE("GPL");
-#define INPUT_DEVICES 256
+#define INPUT_MAX_CHAR_DEVICES 1024
+#define INPUT_FIRST_DYNAMIC_DEV 256
+static DEFINE_IDA(input_ida);
static LIST_HEAD(input_dev_list);
static LIST_HEAD(input_handler_list);
@@ -45,8 +48,6 @@ static LIST_HEAD(input_handler_list);
*/
static DEFINE_MUTEX(input_mutex);
-static struct input_handler *input_table[8];
-
static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };
static inline int is_event_supported(unsigned int code,
@@ -1218,7 +1219,7 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);
if (handler->filter)
seq_puts(seq, " (filter)");
- if (handler->fops)
+ if (handler->legacy_minors)
seq_printf(seq, " Minor=%d", handler->minor);
seq_putc(seq, '\n');
@@ -2016,22 +2017,14 @@ EXPORT_SYMBOL(input_unregister_device);
int input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
- int retval;
+ int error;
- retval = mutex_lock_interruptible(&input_mutex);
- if (retval)
- return retval;
+ error = mutex_lock_interruptible(&input_mutex);
+ if (error)
+ return error;
INIT_LIST_HEAD(&handler->h_list);
- if (handler->fops != NULL) {
- if (input_table[handler->minor >> 5]) {
- retval = -EBUSY;
- goto out;
- }
- input_table[handler->minor >> 5] = handler;
- }
-
list_add_tail(&handler->node, &input_handler_list);
list_for_each_entry(dev, &input_dev_list, node)
@@ -2039,9 +2032,8 @@ int input_register_handler(struct input_handler *handler)
input_wakeup_procfs_readers();
- out:
mutex_unlock(&input_mutex);
- return retval;
+ return 0;
}
EXPORT_SYMBOL(input_register_handler);
@@ -2064,9 +2056,6 @@ void input_unregister_handler(struct input_handler *handler)
list_del_init(&handler->node);
- if (handler->fops != NULL)
- input_table[handler->minor >> 5] = NULL;
-
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
@@ -2183,51 +2172,52 @@ void input_unregister_handle(struct input_handle *handle)
}
EXPORT_SYMBOL(input_unregister_handle);
-static int input_open_file(struct inode *inode, struct file *file)
+/**
+ * input_get_new_minor - allocates a new input minor number
+ * @legacy_base: beginning or the legacy range to be searched
+ * @legacy_num: size of legacy range
+ * @allow_dynamic: whether we can also take ID from the dynamic range
+ *
+ * This function allocates a new device minor for from input major namespace.
+ * Caller can request legacy minor by specifying @legacy_base and @legacy_num
+ * parameters and whether ID can be allocated from dynamic range if there are
+ * no free IDs in legacy range.
+ */
+int input_get_new_minor(int legacy_base, unsigned int legacy_num,
+ bool allow_dynamic)
{
- struct input_handler *handler;
- const struct file_operations *old_fops, *new_fops = NULL;
- int err;
-
- err = mutex_lock_interruptible(&input_mutex);
- if (err)
- return err;
-
- /* No load-on-demand here? */
- handler = input_table[iminor(inode) >> 5];
- if (handler)
- new_fops = fops_get(handler->fops);
-
- mutex_unlock(&input_mutex);
-
/*
- * That's _really_ odd. Usually NULL ->open means "nothing special",
- * not "no device". Oh, well...
+ * This function should be called from input handler's ->connect()
+ * methods, which are serialized with input_mutex, so no additional
+ * locking is needed here.
*/
- if (!new_fops || !new_fops->open) {
- fops_put(new_fops);
- err = -ENODEV;
- goto out;
+ if (legacy_base >= 0) {
+ int minor = ida_simple_get(&input_ida,
+ legacy_base,
+ legacy_base + legacy_num,
+ GFP_KERNEL);
+ if (minor >= 0 || !allow_dynamic)
+ return minor;
}
- old_fops = file->f_op;
- file->f_op = new_fops;
-
- err = new_fops->open(inode, file);
- if (err) {
- fops_put(file->f_op);
- file->f_op = fops_get(old_fops);
- }
- fops_put(old_fops);
-out:
- return err;
+ return ida_simple_get(&input_ida,
+ INPUT_FIRST_DYNAMIC_DEV, INPUT_MAX_CHAR_DEVICES,
+ GFP_KERNEL);
}
+EXPORT_SYMBOL(input_get_new_minor);
-static const struct file_operations input_fops = {
- .owner = THIS_MODULE,
- .open = input_open_file,
- .llseek = noop_llseek,
-};
+/**
+ * input_free_minor - release previously allocated minor
+ * @minor: minor to be released
+ *
+ * This function releases previously allocated input minor so that it can be
+ * reused later.
+ */
+void input_free_minor(unsigned int minor)
+{
+ ida_simple_remove(&input_ida, minor);
+}
+EXPORT_SYMBOL(input_free_minor);
static int __init input_init(void)
{
@@ -2243,7 +2233,8 @@ static int __init input_init(void)
if (err)
goto fail1;
- err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
+ err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),
+ INPUT_MAX_CHAR_DEVICES, "input");
if (err) {
pr_err("unable to register char major %d", INPUT_MAJOR);
goto fail2;
@@ -2259,7 +2250,8 @@ static int __init input_init(void)
static void __exit input_exit(void)
{
input_proc_exit();
- unregister_chrdev(INPUT_MAJOR, "input");
+ unregister_chrdev_region(MKDEV(INPUT_MAJOR, 0),
+ INPUT_MAX_CHAR_DEVICES);
class_unregister(&input_class);
}
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 78f323ea1e4b..b62b5891f399 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -27,6 +27,7 @@
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/device.h>
+#include <linux/cdev.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Joystick device interfaces");
@@ -39,13 +40,13 @@ MODULE_LICENSE("GPL");
struct joydev {
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;
struct js_corr corr[ABS_CNT];
@@ -70,9 +71,6 @@ struct joydev_client {
struct list_head node;
};
-static struct joydev *joydev_table[JOYDEV_MINORS];
-static DEFINE_MUTEX(joydev_table_mutex);
-
static int joydev_correct(int value, struct js_corr *corr)
{
switch (corr->type) {
@@ -252,30 +250,14 @@ static int joydev_release(struct inode *inode, struct file *file)
static int joydev_open(struct inode *inode, struct file *file)
{
+ struct joydev *joydev =
+ container_of(inode->i_cdev, struct joydev, cdev);
struct joydev_client *client;
- struct joydev *joydev;
- int i = iminor(inode) - JOYDEV_MINOR_BASE;
int error;
- if (i >= JOYDEV_MINORS)
- return -ENODEV;
-
- error = mutex_lock_interruptible(&joydev_table_mutex);
- if (error)
- return error;
- joydev = joydev_table[i];
- if (joydev)
- get_device(&joydev->dev);
- mutex_unlock(&joydev_table_mutex);
-
- if (!joydev)
- return -ENODEV;
-
client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
- if (!client) {
- error = -ENOMEM;
- goto err_put_joydev;
- }
+ if (!client)
+ return -ENOMEM;
spin_lock_init(&client->buffer_lock);
client->joydev = joydev;
@@ -288,13 +270,12 @@ static int joydev_open(struct inode *inode, struct file *file)
file->private_data = client;
nonseekable_open(inode, file);
+ get_device(&joydev->dev);
return 0;
err_free_client:
joydev_detach_client(joydev, client);
kfree(client);
- err_put_joydev:
- put_device(&joydev->dev);
return error;
}
@@ -742,19 +723,6 @@ static const struct file_operations joydev_fops = {
.llseek = no_llseek,
};
-static int joydev_install_chrdev(struct joydev *joydev)
-{
- joydev_table[joydev->minor] = joydev;
- return 0;
-}
-
-static void joydev_remove_chrdev(struct joydev *joydev)
-{
- mutex_lock(&joydev_table_mutex);
- joydev_table[joydev->minor] = NULL;
- mutex_unlock(&joydev_table_mutex);
-}
-
/*
* Mark device non-existent. This disables writes, ioctls and
* prevents new users from opening the device. Already posted
@@ -773,7 +741,8 @@ static void joydev_cleanup(struct joydev *joydev)
joydev_mark_dead(joydev);
joydev_hangup(joydev);
- joydev_remove_chrdev(joydev);
+
+ cdev_del(&joydev->cdev);
/* joydev is marked dead so no one else accesses joydev->open */
if (joydev->open)
@@ -798,30 +767,33 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct joydev *joydev;
- int i, j, t, minor;
+ int i, j, t, minor, dev_no;
int error;
- for (minor = 0; minor < JOYDEV_MINORS; minor++)
- if (!joydev_table[minor])
- break;
-
- if (minor == JOYDEV_MINORS) {
- pr_err("no more free joydev devices\n");
- return -ENFILE;
+ minor = input_get_new_minor(JOYDEV_MINOR_BASE, JOYDEV_MINORS, true);
+ if (minor < 0) {
+ error = minor;
+ pr_err("failed to reserve new minor: %d\n", error);
+ return error;
}
joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
- if (!joydev)
- return -ENOMEM;
+ if (!joydev) {
+ error = -ENOMEM;
+ goto err_free_minor;
+ }
INIT_LIST_HEAD(&joydev->client_list);
spin_lock_init(&joydev->client_lock);
mutex_init(&joydev->mutex);
init_waitqueue_head(&joydev->wait);
-
- dev_set_name(&joydev->dev, "js%d", minor);
joydev->exist = true;
- joydev->minor = minor;
+
+ dev_no = minor;
+ /* Normalize device number if it falls into legacy range */
+ if (dev_no < JOYDEV_MINOR_BASE + JOYDEV_MINORS)
+ dev_no -= JOYDEV_MINOR_BASE;
+ dev_set_name(&joydev->dev, "js%d", dev_no);
joydev->handle.dev = input_get_device(dev);
joydev->handle.name = dev_name(&joydev->dev);
@@ -875,7 +847,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
}
}
- joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
+ joydev->dev.devt = MKDEV(INPUT_MAJOR, minor);
joydev->dev.class = &input_class;
joydev->dev.parent = &dev->dev;
joydev->dev.release = joydev_free;
@@ -885,7 +857,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
if (error)
goto err_free_joydev;
- error = joydev_install_chrdev(joydev);
+ cdev_init(&joydev->cdev, &joydev_fops);
+ error = cdev_add(&joydev->cdev, joydev->dev.devt, 1);
if (error)
goto err_unregister_handle;
@@ -901,6 +874,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
input_unregister_handle(&joydev->handle);
err_free_joydev:
put_device(&joydev->dev);
+ err_free_minor:
+ input_free_minor(minor);
return error;
}
@@ -910,6 +885,7 @@ static void joydev_disconnect(struct input_handle *handle)
device_del(&joydev->dev);
joydev_cleanup(joydev);
+ input_free_minor(MINOR(joydev->dev.devt));
input_unregister_handle(handle);
put_device(&joydev->dev);
}
@@ -961,7 +937,7 @@ static struct input_handler joydev_handler = {
.match = joydev_match,
.connect = joydev_connect,
.disconnect = joydev_disconnect,
- .fops = &joydev_fops,
+ .legacy_minors = true,
.minor = JOYDEV_MINOR_BASE,
.name = "joydev",
.id_table = joydev_ids,
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index 277e26dc910e..9d7a111486f7 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -431,6 +431,12 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
goto err_unmap_base;
}
+ error = clk_prepare(keypad->clk);
+ if (error) {
+ dev_err(&pdev->dev, "keypad clock prepare failed\n");
+ goto err_put_clk;
+ }
+
keypad->input_dev = input_dev;
keypad->pdev = pdev;
keypad->row_shift = row_shift;
@@ -461,7 +467,7 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
keypad->keycodes, input_dev);
if (error) {
dev_err(&pdev->dev, "failed to build keymap\n");
- goto err_put_clk;
+ goto err_unprepare_clk;
}
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
@@ -503,6 +509,8 @@ err_free_irq:
pm_runtime_disable(&pdev->dev);
device_init_wakeup(&pdev->dev, 0);
platform_set_drvdata(pdev, NULL);
+err_unprepare_clk:
+ clk_unprepare(keypad->clk);
err_put_clk:
clk_put(keypad->clk);
samsung_keypad_dt_gpio_free(keypad);
@@ -531,6 +539,7 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev)
*/
free_irq(keypad->irq, keypad);
+ clk_unprepare(keypad->clk);
clk_put(keypad->clk);
samsung_keypad_dt_gpio_free(keypad);
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 964e43d81e29..a1b4c37956b2 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,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);
}
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 0d3219f29744..9edf9806cff9 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -172,6 +172,76 @@ static void wacom_close(struct input_dev *dev)
}
/*
+ * Calculate the resolution of the X or Y axis, given appropriate HID data.
+ * This function is little more than hidinput_calc_abs_res stripped down.
+ */
+static int wacom_calc_hid_res(int logical_extents, int physical_extents,
+ unsigned char unit, unsigned char exponent)
+{
+ int prev, unit_exponent;
+
+ /* Check if the extents are sane */
+ if (logical_extents <= 0 || physical_extents <= 0)
+ return 0;
+
+ /* Get signed value of nybble-sized twos-compliment exponent */
+ unit_exponent = exponent;
+ if (unit_exponent > 7)
+ unit_exponent -= 16;
+
+ /* Convert physical_extents to millimeters */
+ if (unit == 0x11) { /* If centimeters */
+ unit_exponent += 1;
+ } else if (unit == 0x13) { /* If inches */
+ prev = physical_extents;
+ physical_extents *= 254;
+ if (physical_extents < prev)
+ return 0;
+ unit_exponent -= 1;
+ } else {
+ return 0;
+ }
+
+ /* Apply negative unit exponent */
+ for (; unit_exponent < 0; unit_exponent++) {
+ prev = logical_extents;
+ logical_extents *= 10;
+ if (logical_extents < prev)
+ return 0;
+ }
+ /* Apply positive unit exponent */
+ for (; unit_exponent > 0; unit_exponent--) {
+ prev = physical_extents;
+ physical_extents *= 10;
+ if (physical_extents < prev)
+ return 0;
+ }
+
+ /* Calculate resolution */
+ return logical_extents / physical_extents;
+}
+
+/*
+ * The physical dimension specified by the HID descriptor is likely not in
+ * the "100th of a mm" units expected by wacom_calculate_touch_res. This
+ * function adjusts the value of [xy]_phy based on the unit and exponent
+ * provided by the HID descriptor. If an error occurs durring conversion
+ * (e.g. from the unit being left unspecified) [xy]_phy is not modified.
+ */
+static void wacom_fix_phy_from_hid(struct wacom_features *features)
+{
+ int xres = wacom_calc_hid_res(features->x_max, features->x_phy,
+ features->unit, features->unitExpo);
+ int yres = wacom_calc_hid_res(features->y_max, features->y_phy,
+ features->unit, features->unitExpo);
+
+ if (xres > 0 && yres > 0) {
+ features->x_phy = (100 * features->x_max) / xres;
+ features->y_phy = (100 * features->y_max) / yres;
+ }
+}
+
+/*
* Static values for max X/Y and resolution of Pen interface is stored in
* features. This mean physical size of active area can be computed.
* This is useful to do when Pen and Touch have same active area of tablet.
@@ -432,56 +502,52 @@ static int wacom_parse_hid(struct usb_interface *intf,
return result;
}
-static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features)
+static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int length, int mode)
{
unsigned char *rep_data;
- int limit = 0, report_id = 2;
- int error = -ENOMEM;
+ int error = -ENOMEM, limit = 0;
- rep_data = kmalloc(4, GFP_KERNEL);
+ rep_data = kzalloc(length, GFP_KERNEL);
if (!rep_data)
return error;
- /* ask to report Wacom data */
+ rep_data[0] = report_id;
+ rep_data[1] = mode;
+
+ do {
+ error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
+ report_id, rep_data, length, 1);
+ if (error >= 0)
+ error = wacom_get_report(intf, WAC_HID_FEATURE_REPORT,
+ report_id, rep_data, length, 1);
+ } while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES);
+
+ kfree(rep_data);
+
+ return error < 0 ? error : 0;
+}
+
+/*
+ * Switch the tablet into its most-capable mode. Wacom tablets are
+ * typically configured to power-up in a mode which sends mouse-like
+ * reports to the OS. To get absolute position, pressure data, etc.
+ * from the tablet, it is necessary to switch the tablet out of this
+ * mode and into one which sends the full range of tablet data.
+ */
+static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features)
+{
if (features->device_type == BTN_TOOL_FINGER) {
- /* if it is an MT Tablet PC touch */
if (features->type > TABLETPC) {
- do {
- rep_data[0] = 3;
- rep_data[1] = 4;
- rep_data[2] = 0;
- rep_data[3] = 0;
- report_id = 3;
- error = wacom_set_report(intf,
- WAC_HID_FEATURE_REPORT,
- report_id,
- rep_data, 4, 1);
- if (error >= 0)
- error = wacom_get_report(intf,
- WAC_HID_FEATURE_REPORT,
- report_id,
- rep_data, 4, 1);
- } while ((error < 0 || rep_data[1] != 4) &&
- limit++ < WAC_MSG_RETRIES);
+ /* MT Tablet PC touch */
+ return wacom_set_device_mode(intf, 3, 4, 4);
+ }
+ } else if (features->device_type == BTN_TOOL_PEN) {
+ if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
+ return wacom_set_device_mode(intf, 2, 2, 2);
}
- } else if (features->type <= BAMBOO_PT &&
- features->type != WIRELESS &&
- features->device_type == BTN_TOOL_PEN) {
- do {
- rep_data[0] = 2;
- rep_data[1] = 2;
- error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
- report_id, rep_data, 2, 1);
- if (error >= 0)
- error = wacom_get_report(intf,
- WAC_HID_FEATURE_REPORT,
- report_id, rep_data, 2, 1);
- } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES);
}
- kfree(rep_data);
-
- return error < 0 ? error : 0;
+ return 0;
}
static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
@@ -531,6 +597,7 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
error = wacom_parse_hid(intf, hid_desc, features);
if (error)
goto out;
+ wacom_fix_phy_from_hid(features);
out:
return error;
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 08b462b6c0d8..c3468c8dbd89 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -25,6 +25,11 @@
#define WACOM_INTUOS_RES 100
#define WACOM_INTUOS3_RES 200
+/* Scale factor relating reported contact size to logical contact area.
+ * 2^14/pi is a good approximation on Intuos5 and 3rd-gen Bamboo
+ */
+#define WACOM_CONTACT_AREA_SCALE 2607
+
static int wacom_penpartner_irq(struct wacom_wac *wacom)
{
unsigned char *data = wacom->data;
@@ -326,7 +331,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
/* Enter report */
if ((data[1] & 0xfc) == 0xc0) {
- if (features->type >= INTUOS5S && features->type <= INTUOS5L)
+ if (features->quirks == WACOM_QUIRK_MULTI_INPUT)
wacom->shared->stylus_in_proximity = true;
/* serial number of the tool */
@@ -414,7 +419,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
/* Exit report */
if ((data[1] & 0xfe) == 0x80) {
- if (features->type >= INTUOS5S && features->type <= INTUOS5L)
+ if (features->quirks == WACOM_QUIRK_MULTI_INPUT)
wacom->shared->stylus_in_proximity = false;
/*
@@ -1043,11 +1048,19 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
if (touch) {
int x = (data[2] << 4) | (data[4] >> 4);
int y = (data[3] << 4) | (data[4] & 0x0f);
- int w = data[6];
+ int a = data[5];
+
+ // "a" is a scaled-down area which we assume is roughly
+ // circular and which can be described as: a=(pi*r^2)/C.
+ int x_res = input_abs_get_res(input, ABS_X);
+ int y_res = input_abs_get_res(input, ABS_Y);
+ int width = 2 * int_sqrt(a * WACOM_CONTACT_AREA_SCALE);
+ int height = width * y_res / x_res;
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
- input_report_abs(input, ABS_MT_TOUCH_MAJOR, w);
+ input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
+ input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
}
}
@@ -1533,7 +1546,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
input_mt_init_slots(input_dev, features->touch_max, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
- 0, 255, 0, 0);
+ 0, features->x_max, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
+ 0, features->y_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, features->x_max,
@@ -1641,7 +1656,10 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev,
ABS_MT_TOUCH_MAJOR,
- 0, 255, 0, 0);
+ 0, features->x_max, 0, 0);
+ input_set_abs_params(input_dev,
+ ABS_MT_TOUCH_MINOR,
+ 0, features->y_max, 0, 0);
}
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index e92615d0b1b0..1df2396af008 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -320,10 +320,8 @@ static bool mxt_object_writable(unsigned int type)
static void mxt_dump_message(struct device *dev,
struct mxt_message *message)
{
- dev_dbg(dev, "reportid: %u\tmessage: %02x %02x %02x %02x %02x %02x %02x\n",
- message->reportid, message->message[0], message->message[1],
- message->message[2], message->message[3], message->message[4],
- message->message[5], message->message[6]);
+ dev_dbg(dev, "reportid: %u\tmessage: %*ph\n",
+ message->reportid, 7, message->message);
}
static int mxt_check_bootloader(struct i2c_client *client,