Commit 0cc8d6a9 authored by Dmitry Torokhov's avatar Dmitry Torokhov

Merge branch 'next' into for-linus

Prepare second set of updates for 3.7 merge window (Wacom driver update
and patches extending number of input minors).
parents dde3ada3 7f8d4cad
...@@ -283,6 +283,9 @@ ...@@ -283,6 +283,9 @@
#define USB_VENDOR_ID_EMS 0x2006 #define USB_VENDOR_ID_EMS 0x2006
#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118 #define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
#define USB_VENDOR_ID_FLATFROG 0x25b5
#define USB_DEVICE_ID_MULTITOUCH_3200 0x0002
#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
......
...@@ -1154,6 +1154,7 @@ static void report_features(struct hid_device *hid) ...@@ -1154,6 +1154,7 @@ static void report_features(struct hid_device *hid)
int hidinput_connect(struct hid_device *hid, unsigned int force) int hidinput_connect(struct hid_device *hid, unsigned int force)
{ {
struct hid_driver *drv = hid->driver;
struct hid_report *report; struct hid_report *report;
struct hid_input *hidinput = NULL; struct hid_input *hidinput = NULL;
struct input_dev *input_dev; struct input_dev *input_dev;
...@@ -1228,6 +1229,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1228,6 +1229,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
* UGCI) cram a lot of unrelated inputs into the * UGCI) cram a lot of unrelated inputs into the
* same interface. */ * same interface. */
hidinput->report = report; hidinput->report = report;
if (drv->input_configured)
drv->input_configured(hid, hidinput);
if (input_register_device(hidinput->input)) if (input_register_device(hidinput->input))
goto out_cleanup; goto out_cleanup;
hidinput = NULL; hidinput = NULL;
...@@ -1235,8 +1238,12 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1235,8 +1238,12 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
} }
} }
if (hidinput && input_register_device(hidinput->input)) if (hidinput) {
goto out_cleanup; if (drv->input_configured)
drv->input_configured(hid, hidinput);
if (input_register_device(hidinput->input))
goto out_cleanup;
}
return 0; return 0;
......
...@@ -392,7 +392,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd ...@@ -392,7 +392,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
__set_bit(EV_ABS, input->evbit); __set_bit(EV_ABS, input->evbit);
error = input_mt_init_slots(input, 16); error = input_mt_init_slots(input, 16, 0);
if (error) if (error)
return error; return error;
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2, input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2,
......
This diff is collapsed.
...@@ -23,11 +23,11 @@ ...@@ -23,11 +23,11 @@
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include <linux/major.h> #include <linux/major.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/cdev.h>
#include "input-compat.h" #include "input-compat.h"
struct evdev { struct evdev {
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 evdev_client __rcu *grab; struct evdev_client __rcu *grab;
...@@ -35,6 +35,7 @@ struct evdev { ...@@ -35,6 +35,7 @@ struct evdev {
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;
}; };
...@@ -51,19 +52,9 @@ struct evdev_client { ...@@ -51,19 +52,9 @@ struct evdev_client {
struct input_event buffer[]; struct input_event buffer[];
}; };
static struct evdev *evdev_table[EVDEV_MINORS]; static void __pass_event(struct evdev_client *client,
static DEFINE_MUTEX(evdev_table_mutex); const struct input_event *event)
static void evdev_pass_event(struct evdev_client *client,
struct input_event *event,
ktime_t mono, ktime_t real)
{ {
event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
mono : real);
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);
client->buffer[client->head++] = *event; client->buffer[client->head++] = *event;
client->head &= client->bufsize - 1; client->head &= client->bufsize - 1;
...@@ -86,42 +77,74 @@ static void evdev_pass_event(struct evdev_client *client, ...@@ -86,42 +77,74 @@ static void evdev_pass_event(struct evdev_client *client,
client->packet_head = client->head; client->packet_head = client->head;
kill_fasync(&client->fasync, SIGIO, POLL_IN); kill_fasync(&client->fasync, SIGIO, POLL_IN);
} }
}
static void evdev_pass_values(struct evdev_client *client,
const struct input_value *vals, unsigned int count,
ktime_t mono, ktime_t real)
{
struct evdev *evdev = client->evdev;
const struct input_value *v;
struct input_event event;
bool wakeup = false;
event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
mono : real);
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);
for (v = vals; v != vals + count; v++) {
event.type = v->type;
event.code = v->code;
event.value = v->value;
__pass_event(client, &event);
if (v->type == EV_SYN && v->code == SYN_REPORT)
wakeup = true;
}
spin_unlock(&client->buffer_lock); spin_unlock(&client->buffer_lock);
if (wakeup)
wake_up_interruptible(&evdev->wait);
} }
/* /*
* Pass incoming event to all connected clients. * Pass incoming events to all connected clients.
*/ */
static void evdev_event(struct input_handle *handle, static void evdev_events(struct input_handle *handle,
unsigned int type, unsigned int code, int value) const struct input_value *vals, unsigned int count)
{ {
struct evdev *evdev = handle->private; struct evdev *evdev = handle->private;
struct evdev_client *client; struct evdev_client *client;
struct input_event event;
ktime_t time_mono, time_real; ktime_t time_mono, time_real;
time_mono = ktime_get(); time_mono = ktime_get();
time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
event.type = type;
event.code = code;
event.value = value;
rcu_read_lock(); rcu_read_lock();
client = rcu_dereference(evdev->grab); client = rcu_dereference(evdev->grab);
if (client) if (client)
evdev_pass_event(client, &event, time_mono, time_real); evdev_pass_values(client, vals, count, time_mono, time_real);
else else
list_for_each_entry_rcu(client, &evdev->client_list, node) list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_event(client, &event, time_mono, time_real); evdev_pass_values(client, vals, count,
time_mono, time_real);
rcu_read_unlock(); rcu_read_unlock();
}
if (type == EV_SYN && code == SYN_REPORT) /*
wake_up_interruptible(&evdev->wait); * Pass incoming event to all connected clients.
*/
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct input_value vals[] = { { type, code, value } };
evdev_events(handle, vals, 1);
} }
static int evdev_fasync(int fd, struct file *file, int on) static int evdev_fasync(int fd, struct file *file, int on)
...@@ -285,35 +308,16 @@ static unsigned int evdev_compute_buffer_size(struct input_dev *dev) ...@@ -285,35 +308,16 @@ static unsigned int evdev_compute_buffer_size(struct input_dev *dev)
static int evdev_open(struct inode *inode, struct file *file) 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; struct evdev_client *client;
int i = iminor(inode) - EVDEV_MINOR_BASE;
unsigned int bufsize;
int error; 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) + client = kzalloc(sizeof(struct evdev_client) +
bufsize * sizeof(struct input_event), bufsize * sizeof(struct input_event),
GFP_KERNEL); GFP_KERNEL);
if (!client) { if (!client)
error = -ENOMEM; return -ENOMEM;
goto err_put_evdev;
}
client->bufsize = bufsize; client->bufsize = bufsize;
spin_lock_init(&client->buffer_lock); spin_lock_init(&client->buffer_lock);
...@@ -327,13 +331,12 @@ static int evdev_open(struct inode *inode, struct file *file) ...@@ -327,13 +331,12 @@ static int evdev_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(&evdev->dev);
return 0; return 0;
err_free_client: err_free_client:
evdev_detach_client(evdev, client); evdev_detach_client(evdev, client);
kfree(client); kfree(client);
err_put_evdev:
put_device(&evdev->dev);
return error; return error;
} }
...@@ -653,20 +656,22 @@ static int evdev_handle_mt_request(struct input_dev *dev, ...@@ -653,20 +656,22 @@ static int evdev_handle_mt_request(struct input_dev *dev,
unsigned int size, unsigned int size,
int __user *ip) int __user *ip)
{ {
const struct input_mt_slot *mt = dev->mt; const struct input_mt *mt = dev->mt;
unsigned int code; unsigned int code;
int max_slots; int max_slots;
int i; int i;
if (get_user(code, &ip[0])) if (get_user(code, &ip[0]))
return -EFAULT; return -EFAULT;
if (!input_is_mt_value(code)) if (!mt || !input_is_mt_value(code))
return -EINVAL; return -EINVAL;
max_slots = (size - sizeof(__u32)) / sizeof(__s32); max_slots = (size - sizeof(__u32)) / sizeof(__s32);
for (i = 0; i < dev->mtsize && i < max_slots; i++) for (i = 0; i < mt->num_slots && i < max_slots; i++) {
if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i])) int value = input_mt_get_value(&mt->slots[i], code);
if (put_user(value, &ip[1 + i]))
return -EFAULT; return -EFAULT;
}
return 0; return 0;
} }
...@@ -915,26 +920,6 @@ static const struct file_operations evdev_fops = { ...@@ -915,26 +920,6 @@ static const struct file_operations evdev_fops = {
.llseek = no_llseek, .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 * 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
...@@ -953,7 +938,8 @@ static void evdev_cleanup(struct evdev *evdev) ...@@ -953,7 +938,8 @@ static void evdev_cleanup(struct evdev *evdev)
evdev_mark_dead(evdev); evdev_mark_dead(evdev);
evdev_hangup(evdev); evdev_hangup(evdev);
evdev_remove_chrdev(evdev);
cdev_del(&evdev->cdev);
/* evdev is marked dead so no one else accesses evdev->open */ /* evdev is marked dead so no one else accesses evdev->open */
if (evdev->open) { if (evdev->open) {
...@@ -964,43 +950,47 @@ static void evdev_cleanup(struct evdev *evdev) ...@@ -964,43 +950,47 @@ static void evdev_cleanup(struct evdev *evdev)
/* /*
* Create new evdev device. Note that input core serializes calls * 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, static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id) const struct input_device_id *id)
{ {
struct evdev *evdev; struct evdev *evdev;
int minor; int minor;
int dev_no;
int error; int error;
for (minor = 0; minor < EVDEV_MINORS; minor++) minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
if (!evdev_table[minor]) if (minor < 0) {
break; error = minor;
pr_err("failed to reserve new minor: %d\n", error);
if (minor == EVDEV_MINORS) { return error;
pr_err("no more free evdev devices\n");
return -ENFILE;
} }
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
if (!evdev) if (!evdev) {
return -ENOMEM; error = -ENOMEM;
goto err_free_minor;
}
INIT_LIST_HEAD(&evdev->client_list); INIT_LIST_HEAD(&evdev->client_list);
spin_lock_init(&evdev->client_lock); spin_lock_init(&evdev->client_lock);
mutex_init(&evdev->mutex); mutex_init(&evdev->mutex);
init_waitqueue_head(&evdev->wait); init_waitqueue_head(&evdev->wait);
dev_set_name(&evdev->dev, "event%d", minor);
evdev->exist = true; 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.dev = input_get_device(dev);
evdev->handle.name = dev_name(&evdev->dev); evdev->handle.name = dev_name(&evdev->dev);
evdev->handle.handler = handler; evdev->handle.handler = handler;
evdev->handle.private = evdev; 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.class = &input_class;
evdev->dev.parent = &dev->dev; evdev->dev.parent = &dev->dev;
evdev->dev.release = evdev_free; evdev->dev.release = evdev_free;
...@@ -1010,7 +1000,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, ...@@ -1010,7 +1000,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
if (error) if (error)
goto err_free_evdev; 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) if (error)
goto err_unregister_handle; goto err_unregister_handle;
...@@ -1026,6 +1017,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, ...@@ -1026,6 +1017,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
input_unregister_handle(&evdev->handle); input_unregister_handle(&evdev->handle);
err_free_evdev: err_free_evdev:
put_device(&evdev->dev); put_device(&evdev->dev);
err_free_minor:
input_free_minor(minor);
return error; return error;
} }
...@@ -1035,6 +1028,7 @@ static void evdev_disconnect(struct input_handle *handle) ...@@ -1035,6 +1028,7 @@ static void evdev_disconnect(struct input_handle *handle)
device_del(&evdev->dev); device_del(&evdev->dev);
evdev_cleanup(evdev); evdev_cleanup(evdev);
input_free_minor(MINOR(evdev->dev.devt));
input_unregister_handle(handle); input_unregister_handle(handle);
put_device(&evdev->dev); put_device(&evdev->dev);
} }
...@@ -1048,9 +1042,10 @@ MODULE_DEVICE_TABLE(input, evdev_ids); ...@@ -1048,9 +1042,10 @@ MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = { static struct input_handler evdev_handler = {
.event = evdev_event, .event = evdev_event,
.events = evdev_events,
.connect = evdev_connect, .connect = evdev_connect,
.disconnect = evdev_disconnect, .disconnect = evdev_disconnect,
.fops = &evdev_fops, .legacy_minors = true,
.minor = EVDEV_MINOR_BASE, .minor = EVDEV_MINOR_BASE,
.name = "evdev", .name = "evdev",
.id_table = evdev_ids, .id_table = evdev_ids,
......
...@@ -14,6 +14,14 @@ ...@@ -14,6 +14,14 @@
#define TRKID_SGN ((TRKID_MAX + 1) >> 1) #define TRKID_SGN ((TRKID_MAX + 1) >> 1)
static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
{
if (dev->absinfo && test_bit(src, dev->absbit)) {
dev->absinfo[dst] = dev->absinfo[src];
dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
}
}
/** /**
* input_mt_init_slots() - initialize MT input slots * input_mt_init_slots() - initialize MT input slots
* @dev: input device supporting MT events and finger tracking * @dev: input device supporting MT events and finger tracking
...@@ -25,29 +33,63 @@ ...@@ -25,29 +33,63 @@
* May be called repeatedly. Returns -EINVAL if attempting to * May be called repeatedly. Returns -EINVAL if attempting to
* reinitialize with a different number of slots. * reinitialize with a different number of slots.
*/ */
int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots) int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
unsigned int flags)
{ {
struct input_mt *mt = dev->mt;
int i; int i;
if (!num_slots) if (!num_slots)
return 0; return 0;
if (dev->mt) if (mt)
return dev->mtsize != num_slots ? -EINVAL : 0; return mt->num_slots != num_slots ? -EINVAL : 0;
dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL); mt = kzalloc(sizeof(*mt) + num_slots * sizeof(*mt->slots), GFP_KERNEL);
if (!dev->mt) if (!mt)
return -ENOMEM; goto err_mem;
dev->mtsize = num_slots; mt->num_slots = num_slots;
mt->flags = flags;
input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0); input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0); input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
input_set_events_per_packet(dev, 6 * num_slots);
if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
__set_bit(EV_KEY, dev->evbit);
__set_bit(BTN_TOUCH, dev->keybit);
copy_abs(dev, ABS_X, ABS_MT_POSITION_X);
copy_abs(dev, ABS_Y, ABS_MT_POSITION_Y);
copy_abs(dev, ABS_PRESSURE, ABS_MT_PRESSURE);
}
if (flags & INPUT_MT_POINTER) {
__set_bit(BTN_TOOL_FINGER, dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
if (num_slots >= 3)
__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
if (num_slots >= 4)
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
if (num_slots >= 5)
__set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
__set_bit(INPUT_PROP_POINTER, dev->propbit);
}
if (flags & INPUT_MT_DIRECT)
__set_bit(INPUT_PROP_DIRECT, dev->propbit);
if (flags & INPUT_MT_TRACK) {
unsigned int n2 = num_slots * num_slots;
mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL);
if (!mt->red)
goto err_mem;
}
/* Mark slots as 'unused' */ /* Mark slots as 'unused' */
for (i = 0; i < num_slots; i++) for (i = 0; i < num_slots; i++)
input_mt_set_value(&dev->mt[i], ABS_MT_TRACKING_ID, -1); input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1);
dev->mt = mt;
return 0; return 0;
err_mem:
kfree(mt);
return -ENOMEM;
} }
EXPORT_SYMBOL(input_mt_init_slots); EXPORT_SYMBOL(input_mt_init_slots);
...@@ -60,11 +102,11 @@ EXPORT_SYMBOL(input_mt_init_slots); ...@@ -60,11 +102,11 @@ EXPORT_SYMBOL(input_mt_init_slots);
*/ */
void input_mt_destroy_slots(struct input_dev *dev) void input_mt_destroy_slots(struct input_dev *dev)
{ {
kfree(dev->mt); if (dev->mt) {
kfree(dev->mt->red);
kfree(dev->mt);
}
dev->mt = NULL; dev->mt = NULL;
dev->mtsize = 0;
dev->slot = 0;
dev->trkid = 0;
} }
EXPORT_SYMBOL(input_mt_destroy_slots); EXPORT_SYMBOL(input_mt_destroy_slots);
...@@ -83,18 +125,24 @@ EXPORT_SYMBOL(input_mt_destroy_slots); ...@@ -83,18 +125,24 @@ EXPORT_SYMBOL(input_mt_destroy_slots);
void input_mt_report_slot_state(struct input_dev *dev, void input_mt_report_slot_state(struct input_dev *dev,
unsigned int tool_type, bool active) unsigned int tool_type, bool active)
{ {
struct input_mt_slot *mt; struct input_mt *mt = dev->mt;
struct input_mt_slot *slot;
int id; int id;
if (!dev->mt || !active) { if (!mt)
return;
slot = &mt->slots[mt->slot];
slot->frame = mt->frame;
if (!active) {
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
return; return;
} }
mt = &dev->mt[dev->slot]; id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
id = input_mt_get_value(mt, ABS_MT_TRACKING_ID); if (id < 0 || input_mt_get_value(slot, ABS_MT_TOOL_TYPE) != tool_type)
if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type) id = input_mt_new_trkid(mt);
id = input_mt_new_trkid(dev);
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id); input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type); input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
...@@ -135,13 +183,19 @@ EXPORT_SYMBOL(input_mt_report_finger_count); ...@@ -135,13 +183,19 @@ EXPORT_SYMBOL(input_mt_report_finger_count);
*/ */
void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
{ {
struct input_mt_slot *oldest = NULL; struct input_mt *mt = dev->mt;
int oldid = dev->trkid; struct input_mt_slot *oldest;
int count = 0; int oldid, count, i;
int i;
if (!mt)
return;
oldest = 0;
oldid = mt->trkid;
count = 0;
for (i = 0; i < dev->mtsize; ++i) { for (i = 0; i < mt->num_slots; ++i) {
struct input_mt_slot *ps = &dev->mt[i]; struct input_mt_slot *ps = &mt->slots[i];
int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID); int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
if (id < 0) if (id < 0)
...@@ -160,13 +214,208 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) ...@@ -160,13 +214,208 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
if (oldest) { if (oldest) {
int x = input_mt_get_value(oldest, ABS_MT_POSITION_X); int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y); int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
input_event(dev, EV_ABS, ABS_X, x); input_event(dev, EV_ABS, ABS_X, x);
input_event(dev, EV_ABS, ABS_Y, y); input_event(dev, EV_ABS, ABS_Y, y);
input_event(dev, EV_ABS, ABS_PRESSURE, p);
if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
input_event(dev, EV_ABS, ABS_PRESSURE, p);
}
} else { } else {
input_event(dev, EV_ABS, ABS_PRESSURE, 0); if (test_bit(ABS_MT_PRESSURE, dev->absbit))
input_event(dev, EV_ABS, ABS_PRESSURE, 0);
} }
} }
EXPORT_SYMBOL(input_mt_report_pointer_emulation); EXPORT_SYMBOL(input_mt_report_pointer_emulation);
/**
* input_mt_sync_frame() - synchronize mt frame
* @dev: input device with allocated MT slots
*
* Close the frame and prepare the internal state for a new one.
* Depending on the flags, marks unused slots as inactive and performs
* pointer emulation.
*/
void input_mt_sync_frame(struct input_dev *dev)
{
struct input_mt *mt = dev->mt;
struct input_mt_slot *s;
if (!mt)
return;
if (mt->flags & INPUT_MT_DROP_UNUSED) {
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
if (s->frame == mt->frame)
continue;
input_mt_slot(dev, s - mt->slots);
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
}
}
input_mt_report_pointer_emulation(dev, (mt->flags & INPUT_MT_POINTER));
mt->frame++;
}
EXPORT_SYMBOL(input_mt_sync_frame);
static int adjust_dual(int *begin, int step, int *end, int eq)
{
int f, *p, s, c;
if (begin == end)
return 0;
f = *begin;
p = begin + step;
s = p == end ? f + 1 : *p;
for (; p != end; p += step)
if (*p < f)
s = f, f = *p;
else if (*p < s)
s = *p;
c = (f + s + 1) / 2;
if (c == 0 || (c > 0 && !eq))
return 0;
if (s < 0)
c *= 2;
for (p = begin; p != end; p += step)
*p -= c;
return (c < s && s <= 0) || (f >= 0 && f < c);
}
static void find_reduced_matrix(int *w, int nr, int nc, int nrc)
{
int i, k, sum;
for (k = 0; k < nrc; k++) {
for (i = 0; i < nr; i++)
adjust_dual(w + i, nr, w + i + nrc, nr <= nc);
sum = 0;
for (i = 0; i < nrc; i += nr)
sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr);
if (!sum)
break;
}
}
static int input_mt_set_matrix(struct input_mt *mt,
const struct input_mt_pos *pos, int num_pos)
{
const struct input_mt_pos *p;
struct input_mt_slot *s;
int *w = mt->red;
int x, y;
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
if (!input_mt_is_active(s))
continue;
x = input_mt_get_value(s, ABS_MT_POSITION_X);
y = input_mt_get_value(s, ABS_MT_POSITION_Y);
for (p = pos; p != pos + num_pos; p++) {
int dx = x - p->x, dy = y - p->y;
*w++ = dx * dx + dy * dy;
}
}
return w - mt->red;
}
static void input_mt_set_slots(struct input_mt *mt,
int *slots, int num_pos)
{
struct input_mt_slot *s;
int *w = mt->red, *p;
for (p = slots; p != slots + num_pos; p++)
*p = -1;
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
if (!input_mt_is_active(s))
continue;
for (p = slots; p != slots + num_pos; p++)
if (*w++ < 0)
*p = s - mt->slots;
}
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
if (input_mt_is_active(s))
continue;
for (p = slots; p != slots + num_pos; p++)
if (*p < 0) {
*p = s - mt->slots;
break;
}
}
}
/**
* input_mt_assign_slots() - perform a best-match assignment
* @dev: input device with allocated MT slots
* @slots: the slot assignment to be filled
* @pos: the position array to match
* @num_pos: number of positions
*
* Performs a best match against the current contacts and returns
* the slot assignment list. New contacts are assigned to unused
* slots.
*
* Returns zero on success, or negative error in case of failure.
*/
int input_mt_assign_slots(struct input_dev *dev, int *slots,
const struct input_mt_pos *pos, int num_pos)
{
struct input_mt *mt = dev->mt;
int nrc;
if (!mt || !mt->red)
return -ENXIO;
if (num_pos > mt->num_slots)
return -EINVAL;
if (num_pos < 1)
return 0;
nrc = input_mt_set_matrix(mt, pos, num_pos);
find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc);
input_mt_set_slots(mt, slots, num_pos);
return 0;
}
EXPORT_SYMBOL(input_mt_assign_slots);
/**
* input_mt_get_slot_by_key() - return slot matching key
* @dev: input device with allocated MT slots
* @key: the key of the sought slot
*
* Returns the slot of the given key, if it exists, otherwise
* set the key on the first unused slot and return.
*
* If no available slot can be found, -1 is returned.
*/
int input_mt_get_slot_by_key(struct input_dev *dev, int key)
{
struct input_mt *mt = dev->mt;
struct input_mt_slot *s;
if (!mt)
return -1;
for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
if (input_mt_is_active(s) && s->key == key)
return s - mt->slots;
for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
if (!input_mt_is_active(s)) {
s->key = key;
return s - mt->slots;
}
return -1;
}
EXPORT_SYMBOL(input_mt_get_slot_by_key);
This diff is collapsed.
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/cdev.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Joystick device interfaces"); MODULE_DESCRIPTION("Joystick device interfaces");
...@@ -39,13 +40,13 @@ MODULE_LICENSE("GPL"); ...@@ -39,13 +40,13 @@ MODULE_LICENSE("GPL");
struct joydev { struct joydev {
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;
struct js_corr corr[ABS_CNT]; struct js_corr corr[ABS_CNT];
...@@ -70,9 +71,6 @@ struct joydev_client { ...@@ -70,9 +71,6 @@ struct joydev_client {
struct list_head node; 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) static int joydev_correct(int value, struct js_corr *corr)
{ {
switch (corr->type) { switch (corr->type) {
...@@ -252,30 +250,14 @@ static int joydev_release(struct inode *inode, struct file *file) ...@@ -252,30 +250,14 @@ static int joydev_release(struct inode *inode, struct file *file)
static int joydev_open(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_client *client;
struct joydev *joydev;
int i = iminor(inode) - JOYDEV_MINOR_BASE;
int error; 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); client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
if (!client) { if (!client)
error = -ENOMEM; return -ENOMEM;
goto err_put_joydev;
}
spin_lock_init(&client->buffer_lock); spin_lock_init(&client->buffer_lock);
client->joydev = joydev; client->joydev = joydev;
...@@ -288,13 +270,12 @@ static int joydev_open(struct inode *inode, struct file *file) ...@@ -288,13 +270,12 @@ static int joydev_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(&joydev->dev);
return 0; return 0;
err_free_client: err_free_client:
joydev_detach_client(joydev, client); joydev_detach_client(joydev, client);
kfree(client); kfree(client);
err_put_joydev:
put_device(&joydev->dev);
return error; return error;
} }
...@@ -742,19 +723,6 @@ static const struct file_operations joydev_fops = { ...@@ -742,19 +723,6 @@ static const struct file_operations joydev_fops = {
.llseek = no_llseek, .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 * 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
...@@ -773,7 +741,8 @@ static void joydev_cleanup(struct joydev *joydev) ...@@ -773,7 +741,8 @@ static void joydev_cleanup(struct joydev *joydev)
joydev_mark_dead(joydev); joydev_mark_dead(joydev);
joydev_hangup(joydev); joydev_hangup(joydev);
joydev_remove_chrdev(joydev);
cdev_del(&joydev->cdev);
/* joydev is marked dead so no one else accesses joydev->open */ /* joydev is marked dead so no one else accesses joydev->open */
if (joydev->open) if (joydev->open)
...@@ -798,30 +767,33 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, ...@@ -798,30 +767,33 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id) const struct input_device_id *id)
{ {
struct joydev *joydev; struct joydev *joydev;
int i, j, t, minor; int i, j, t, minor, dev_no;
int error; int error;
for (minor = 0; minor < JOYDEV_MINORS; minor++) minor = input_get_new_minor(JOYDEV_MINOR_BASE, JOYDEV_MINORS, true);
if (!joydev_table[minor]) if (minor < 0) {
break; error = minor;
pr_err("failed to reserve new minor: %d\n", error);
if (minor == JOYDEV_MINORS) { return error;
pr_err("no more free joydev devices\n");
return -ENFILE;
} }
joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
if (!joydev) if (!joydev) {
return -ENOMEM; error = -ENOMEM;
goto err_free_minor;
}
INIT_LIST_HEAD(&joydev->client_list); INIT_LIST_HEAD(&joydev->client_list);
spin_lock_init(&joydev->client_lock); spin_lock_init(&joydev->client_lock);
mutex_init(&joydev->mutex); mutex_init(&joydev->mutex);
init_waitqueue_head(&joydev->wait); init_waitqueue_head(&joydev->wait);
dev_set_name(&joydev->dev, "js%d", minor);
joydev->exist = true; 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.dev = input_get_device(dev);
joydev->handle.name = dev_name(&joydev->dev); joydev->handle.name = dev_name(&joydev->dev);
...@@ -875,7 +847,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *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.class = &input_class;
joydev->dev.parent = &dev->dev; joydev->dev.parent = &dev->dev;
joydev->dev.release = joydev_free; joydev->dev.release = joydev_free;
...@@ -885,7 +857,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, ...@@ -885,7 +857,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
if (error) if (error)
goto err_free_joydev; 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) if (error)
goto err_unregister_handle; goto err_unregister_handle;
...@@ -901,6 +874,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, ...@@ -901,6 +874,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
input_unregister_handle(&joydev->handle); input_unregister_handle(&joydev->handle);
err_free_joydev: err_free_joydev:
put_device(&joydev->dev); put_device(&joydev->dev);
err_free_minor:
input_free_minor(minor);
return error; return error;
} }
...@@ -910,6 +885,7 @@ static void joydev_disconnect(struct input_handle *handle) ...@@ -910,6 +885,7 @@ static void joydev_disconnect(struct input_handle *handle)
device_del(&joydev->dev); device_del(&joydev->dev);
joydev_cleanup(joydev); joydev_cleanup(joydev);
input_free_minor(MINOR(joydev->dev.devt));
input_unregister_handle(handle); input_unregister_handle(handle);
put_device(&joydev->dev); put_device(&joydev->dev);
} }
...@@ -961,7 +937,7 @@ static struct input_handler joydev_handler = { ...@@ -961,7 +937,7 @@ static struct input_handler joydev_handler = {
.match = joydev_match, .match = joydev_match,
.connect = joydev_connect, .connect = joydev_connect,
.disconnect = joydev_disconnect, .disconnect = joydev_disconnect,
.fops = &joydev_fops, .legacy_minors = true,
.minor = JOYDEV_MINOR_BASE, .minor = JOYDEV_MINOR_BASE,
.name = "joydev", .name = "joydev",
.id_table = joydev_ids, .id_table = joydev_ids,
......
...@@ -431,6 +431,12 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) ...@@ -431,6 +431,12 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
goto err_unmap_base; 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->input_dev = input_dev;
keypad->pdev = pdev; keypad->pdev = pdev;
keypad->row_shift = row_shift; keypad->row_shift = row_shift;
...@@ -461,7 +467,7 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) ...@@ -461,7 +467,7 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
keypad->keycodes, input_dev); keypad->keycodes, input_dev);
if (error) { if (error) {
dev_err(&pdev->dev, "failed to build keymap\n"); 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); input_set_capability(input_dev, EV_MSC, MSC_SCAN);
...@@ -503,6 +509,8 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) ...@@ -503,6 +509,8 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
device_init_wakeup(&pdev->dev, 0); device_init_wakeup(&pdev->dev, 0);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
err_unprepare_clk:
clk_unprepare(keypad->clk);
err_put_clk: err_put_clk:
clk_put(keypad->clk); clk_put(keypad->clk);
samsung_keypad_dt_gpio_free(keypad); samsung_keypad_dt_gpio_free(keypad);
...@@ -531,6 +539,7 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev) ...@@ -531,6 +539,7 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev)
*/ */
free_irq(keypad->irq, keypad); free_irq(keypad->irq, keypad);
clk_unprepare(keypad->clk);
clk_put(keypad->clk); clk_put(keypad->clk);
samsung_keypad_dt_gpio_free(keypad); samsung_keypad_dt_gpio_free(keypad);
......
...@@ -416,7 +416,7 @@ static int uinput_setup_device(struct uinput_device *udev, ...@@ -416,7 +416,7 @@ static int uinput_setup_device(struct uinput_device *udev,
goto exit; goto exit;
if (test_bit(ABS_MT_SLOT, dev->absbit)) { if (test_bit(ABS_MT_SLOT, dev->absbit)) {
int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
input_mt_init_slots(dev, nslot); input_mt_init_slots(dev, nslot, 0);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60); input_set_events_per_packet(dev, 60);
} }
......
...@@ -1620,7 +1620,7 @@ int alps_init(struct psmouse *psmouse) ...@@ -1620,7 +1620,7 @@ int alps_init(struct psmouse *psmouse)
case ALPS_PROTO_V3: case ALPS_PROTO_V3:
case ALPS_PROTO_V4: case ALPS_PROTO_V4:
set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
input_mt_init_slots(dev1, 2); input_mt_init_slots(dev1, 2, 0);
input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0); input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0); input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0);
......
This diff is collapsed.
...@@ -1004,7 +1004,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) ...@@ -1004,7 +1004,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
ETP_WMAX_V2, 0, 0); ETP_WMAX_V2, 0, 0);
} }
input_mt_init_slots(dev, 2); input_mt_init_slots(dev, 2, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
break; break;
...@@ -1035,7 +1035,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) ...@@ -1035,7 +1035,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
ETP_WMAX_V2, 0, 0); ETP_WMAX_V2, 0, 0);
/* Multitouch capable pad, up to 5 fingers. */ /* Multitouch capable pad, up to 5 fingers. */
input_mt_init_slots(dev, ETP_MAX_FINGERS); input_mt_init_slots(dev, ETP_MAX_FINGERS, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
input_abs_set_res(dev, ABS_MT_POSITION_X, x_res); input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
......
...@@ -971,7 +971,7 @@ static int fsp_set_input_params(struct psmouse *psmouse) ...@@ -971,7 +971,7 @@ static int fsp_set_input_params(struct psmouse *psmouse)
input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0); input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0); input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0);
input_mt_init_slots(dev, 2); input_mt_init_slots(dev, 2, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0);
} }
......
...@@ -1247,7 +1247,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) ...@@ -1247,7 +1247,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
input_mt_init_slots(dev, 2); input_mt_init_slots(dev, 2, 0);
set_abs_position_params(dev, priv, ABS_MT_POSITION_X, set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
ABS_MT_POSITION_Y); ABS_MT_POSITION_Y);
/* Image sensors can report per-contact pressure */ /* Image sensors can report per-contact pressure */
...@@ -1259,7 +1259,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) ...@@ -1259,7 +1259,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
} else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
/* Non-image sensors with AGM use semi-mt */ /* Non-image sensors with AGM use semi-mt */
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit); __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
input_mt_init_slots(dev, 2); input_mt_init_slots(dev, 2, 0);
set_abs_position_params(dev, priv, ABS_MT_POSITION_X, set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
ABS_MT_POSITION_Y); ABS_MT_POSITION_Y);
} }
......
This diff is collapsed.
...@@ -171,6 +171,76 @@ static void wacom_close(struct input_dev *dev) ...@@ -171,6 +171,76 @@ static void wacom_close(struct input_dev *dev)
usb_autopm_put_interface(wacom->intf); usb_autopm_put_interface(wacom->intf);
} }
/*
* 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 * 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. * features. This mean physical size of active area can be computed.
...@@ -432,56 +502,52 @@ static int wacom_parse_hid(struct usb_interface *intf, ...@@ -432,56 +502,52 @@ static int wacom_parse_hid(struct usb_interface *intf,
return result; 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; unsigned char *rep_data;
int limit = 0, report_id = 2; int error = -ENOMEM, limit = 0;
int error = -ENOMEM;
rep_data = kmalloc(4, GFP_KERNEL); rep_data = kzalloc(length, GFP_KERNEL);
if (!rep_data) if (!rep_data)
return error; 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 (features->device_type == BTN_TOOL_FINGER) {
/* if it is an MT Tablet PC touch */
if (features->type > TABLETPC) { if (features->type > TABLETPC) {
do { /* MT Tablet PC touch */
rep_data[0] = 3; return wacom_set_device_mode(intf, 3, 4, 4);
rep_data[1] = 4; }
rep_data[2] = 0; } else if (features->device_type == BTN_TOOL_PEN) {
rep_data[3] = 0; if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
report_id = 3; return wacom_set_device_mode(intf, 2, 2, 2);
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);
} }
} 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 0;
return error < 0 ? error : 0;
} }
static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
...@@ -531,6 +597,7 @@ 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); error = wacom_parse_hid(intf, hid_desc, features);
if (error) if (error)
goto out; goto out;
wacom_fix_phy_from_hid(features);
out: out:
return error; return error;
......
...@@ -25,6 +25,11 @@ ...@@ -25,6 +25,11 @@
#define WACOM_INTUOS_RES 100 #define WACOM_INTUOS_RES 100
#define WACOM_INTUOS3_RES 200 #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) static int wacom_penpartner_irq(struct wacom_wac *wacom)
{ {
unsigned char *data = wacom->data; unsigned char *data = wacom->data;
...@@ -326,7 +331,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) ...@@ -326,7 +331,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
/* Enter report */ /* Enter report */
if ((data[1] & 0xfc) == 0xc0) { 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; wacom->shared->stylus_in_proximity = true;
/* serial number of the tool */ /* serial number of the tool */
...@@ -414,7 +419,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) ...@@ -414,7 +419,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
/* Exit report */ /* Exit report */
if ((data[1] & 0xfe) == 0x80) { 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; wacom->shared->stylus_in_proximity = false;
/* /*
...@@ -1043,11 +1048,19 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data) ...@@ -1043,11 +1048,19 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
if (touch) { if (touch) {
int x = (data[2] << 4) | (data[4] >> 4); int x = (data[2] << 4) | (data[4] >> 4);
int y = (data[3] << 4) | (data[4] & 0x0f); 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_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y); 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);
} }
} }
...@@ -1530,10 +1543,12 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1530,10 +1543,12 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
input_mt_init_slots(input_dev, features->touch_max); input_mt_init_slots(input_dev, features->touch_max, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 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, input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, features->x_max, 0, features->x_max,
...@@ -1575,7 +1590,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1575,7 +1590,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
case TABLETPC2FG: case TABLETPC2FG:
if (features->device_type == BTN_TOOL_FINGER) { if (features->device_type == BTN_TOOL_FINGER) {
input_mt_init_slots(input_dev, features->touch_max); input_mt_init_slots(input_dev, features->touch_max, 0);
input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0); 0, MT_TOOL_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, input_set_abs_params(input_dev, ABS_MT_POSITION_X,
...@@ -1631,7 +1646,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1631,7 +1646,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_FINGER, input_dev->keybit); __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
input_mt_init_slots(input_dev, features->touch_max); input_mt_init_slots(input_dev, features->touch_max, 0);
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
__set_bit(BTN_TOOL_TRIPLETAP, __set_bit(BTN_TOOL_TRIPLETAP,
...@@ -1641,7 +1656,10 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1641,7 +1656,10 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev, input_set_abs_params(input_dev,
ABS_MT_TOUCH_MAJOR, 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, input_set_abs_params(input_dev, ABS_MT_POSITION_X,
......
...@@ -320,10 +320,8 @@ static bool mxt_object_writable(unsigned int type) ...@@ -320,10 +320,8 @@ static bool mxt_object_writable(unsigned int type)
static void mxt_dump_message(struct device *dev, static void mxt_dump_message(struct device *dev,
struct mxt_message *message) struct mxt_message *message)
{ {
dev_dbg(dev, "reportid: %u\tmessage: %02x %02x %02x %02x %02x %02x %02x\n", dev_dbg(dev, "reportid: %u\tmessage: %*ph\n",
message->reportid, message->message[0], message->message[1], message->reportid, 7, message->message);
message->message[2], message->message[3], message->message[4],
message->message[5], message->message[6]);
} }
static int mxt_check_bootloader(struct i2c_client *client, static int mxt_check_bootloader(struct i2c_client *client,
...@@ -1152,7 +1150,7 @@ static int __devinit mxt_probe(struct i2c_client *client, ...@@ -1152,7 +1150,7 @@ static int __devinit mxt_probe(struct i2c_client *client,
/* For multi touch */ /* For multi touch */
num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1; num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
error = input_mt_init_slots(input_dev, num_mt_slots); error = input_mt_init_slots(input_dev, num_mt_slots, 0);
if (error) if (error)
goto err_free_object; goto err_free_object;
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
......
...@@ -571,7 +571,7 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, ...@@ -571,7 +571,7 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, CY_MAXZ, 0, 0); 0, CY_MAXZ, 0, 0);
input_mt_init_slots(input_dev, CY_MAX_ID); input_mt_init_slots(input_dev, CY_MAX_ID, 0);
error = request_threaded_irq(ts->irq, NULL, cyttsp_irq, error = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
......
...@@ -782,7 +782,7 @@ static int __devinit edt_ft5x06_ts_probe(struct i2c_client *client, ...@@ -782,7 +782,7 @@ static int __devinit edt_ft5x06_ts_probe(struct i2c_client *client,
0, tsdata->num_x * 64 - 1, 0, 0); 0, tsdata->num_x * 64 - 1, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, input_set_abs_params(input, ABS_MT_POSITION_Y,
0, tsdata->num_y * 64 - 1, 0, 0); 0, tsdata->num_y * 64 - 1, 0, 0);
error = input_mt_init_slots(input, MAX_SUPPORT_POINTS); error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);
if (error) { if (error) {
dev_err(&client->dev, "Unable to init MT slots.\n"); dev_err(&client->dev, "Unable to init MT slots.\n");
goto err_free_mem; goto err_free_mem;
......
...@@ -204,7 +204,7 @@ static int __devinit egalax_ts_probe(struct i2c_client *client, ...@@ -204,7 +204,7 @@ static int __devinit egalax_ts_probe(struct i2c_client *client,
ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0); ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0);
input_set_abs_params(input_dev, input_set_abs_params(input_dev,
ABS_MT_POSITION_X, 0, EGALAX_MAX_Y, 0, 0); ABS_MT_POSITION_X, 0, EGALAX_MAX_Y, 0, 0);
input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS); input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS, 0);
input_set_drvdata(input_dev, ts); input_set_drvdata(input_dev, ts);
......
...@@ -252,7 +252,7 @@ static int __devinit ili210x_i2c_probe(struct i2c_client *client, ...@@ -252,7 +252,7 @@ static int __devinit ili210x_i2c_probe(struct i2c_client *client,
input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0); input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
/* Multi touch */ /* Multi touch */
input_mt_init_slots(input, MAX_TOUCHES); input_mt_init_slots(input, MAX_TOUCHES, 0);
input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0);
......
...@@ -404,7 +404,7 @@ static int __devinit mms114_probe(struct i2c_client *client, ...@@ -404,7 +404,7 @@ static int __devinit mms114_probe(struct i2c_client *client,
input_set_abs_params(input_dev, ABS_Y, 0, data->pdata->y_size, 0, 0); input_set_abs_params(input_dev, ABS_Y, 0, data->pdata->y_size, 0, 0);
/* For multi touch */ /* For multi touch */
input_mt_init_slots(input_dev, MMS114_MAX_TOUCH); input_mt_init_slots(input_dev, MMS114_MAX_TOUCH, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, MMS114_MAX_AREA, 0, 0); 0, MMS114_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, input_set_abs_params(input_dev, ABS_MT_POSITION_X,
......
...@@ -264,7 +264,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) ...@@ -264,7 +264,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0); input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0);
if (pm->maxcontacts > 1) { if (pm->maxcontacts > 1) {
input_mt_init_slots(pm->dev, pm->maxcontacts); input_mt_init_slots(pm->dev, pm->maxcontacts, 0);
input_set_abs_params(pm->dev, input_set_abs_params(pm->dev,
ABS_MT_POSITION_X, 0, max_x, 0, 0); ABS_MT_POSITION_X, 0, max_x, 0, 0);
input_set_abs_params(pm->dev, input_set_abs_params(pm->dev,
......
...@@ -471,7 +471,7 @@ static int w8001_setup(struct w8001 *w8001) ...@@ -471,7 +471,7 @@ static int w8001_setup(struct w8001 *w8001)
case 5: case 5:
w8001->pktlen = W8001_PKTLEN_TOUCH2FG; w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
input_mt_init_slots(dev, 2); input_mt_init_slots(dev, 2, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X, input_set_abs_params(dev, ABS_MT_POSITION_X,
0, touch.x, 0, 0); 0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, input_set_abs_params(dev, ABS_MT_POSITION_Y,
......
...@@ -414,7 +414,7 @@ struct hid_field { ...@@ -414,7 +414,7 @@ struct hid_field {
__u16 dpad; /* dpad input code */ __u16 dpad; /* dpad input code */
}; };
#define HID_MAX_FIELDS 128 #define HID_MAX_FIELDS 256
struct hid_report { struct hid_report {
struct list_head list; struct list_head list;
...@@ -626,6 +626,7 @@ struct hid_usage_id { ...@@ -626,6 +626,7 @@ struct hid_usage_id {
* @report_fixup: called before report descriptor parsing (NULL means nop) * @report_fixup: called before report descriptor parsing (NULL means nop)
* @input_mapping: invoked on input registering before mapping an usage * @input_mapping: invoked on input registering before mapping an usage
* @input_mapped: invoked on input registering after mapping an usage * @input_mapped: invoked on input registering after mapping an usage
* @input_configured: invoked just before the device is registered
* @feature_mapping: invoked on feature registering * @feature_mapping: invoked on feature registering
* @suspend: invoked on suspend (NULL means nop) * @suspend: invoked on suspend (NULL means nop)
* @resume: invoked on resume if device was not reset (NULL means nop) * @resume: invoked on resume if device was not reset (NULL means nop)
...@@ -670,6 +671,8 @@ struct hid_driver { ...@@ -670,6 +671,8 @@ struct hid_driver {
int (*input_mapped)(struct hid_device *hdev, int (*input_mapped)(struct hid_device *hdev,
struct hid_input *hidinput, struct hid_field *field, struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max); struct hid_usage *usage, unsigned long **bit, int *max);
void (*input_configured)(struct hid_device *hdev,
struct hid_input *hidinput);
void (*feature_mapping)(struct hid_device *hdev, void (*feature_mapping)(struct hid_device *hdev,
struct hid_field *field, struct hid_field *field,
struct hid_usage *usage); struct hid_usage *usage);
......
...@@ -1168,6 +1168,18 @@ struct ff_effect { ...@@ -1168,6 +1168,18 @@ struct ff_effect {
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
/**
* struct input_value - input value representation
* @type: type of value (EV_KEY, EV_ABS, etc)
* @code: the value code
* @value: the value
*/
struct input_value {
__u16 type;
__u16 code;
__s32 value;
};
/** /**
* struct input_dev - represents an input device * struct input_dev - represents an input device
* @name: name of the device * @name: name of the device
...@@ -1203,11 +1215,7 @@ struct ff_effect { ...@@ -1203,11 +1215,7 @@ struct ff_effect {
* software autorepeat * software autorepeat
* @timer: timer for software autorepeat * @timer: timer for software autorepeat
* @rep: current values for autorepeat parameters (delay, rate) * @rep: current values for autorepeat parameters (delay, rate)
* @mt: pointer to array of struct input_mt_slot holding current values * @mt: pointer to multitouch state
* of tracked contacts
* @mtsize: number of MT slots the device uses
* @slot: MT slot currently being transmitted
* @trkid: stores MT tracking ID for the current contact
* @absinfo: array of &struct input_absinfo elements holding information * @absinfo: array of &struct input_absinfo elements holding information
* about absolute axes (current value, min, max, flat, fuzz, * about absolute axes (current value, min, max, flat, fuzz,
* resolution) * resolution)
...@@ -1244,7 +1252,6 @@ struct ff_effect { ...@@ -1244,7 +1252,6 @@ struct ff_effect {
* last user closes the device * last user closes the device
* @going_away: marks devices that are in a middle of unregistering and * @going_away: marks devices that are in a middle of unregistering and
* causes input_open_device*() fail with -ENODEV. * causes input_open_device*() fail with -ENODEV.
* @sync: set to %true when there were no new events since last EV_SYN
* @dev: driver model's view of this device * @dev: driver model's view of this device
* @h_list: list of input handles associated with the device. When * @h_list: list of input handles associated with the device. When
* accessing the list dev->mutex must be held * accessing the list dev->mutex must be held
...@@ -1287,10 +1294,7 @@ struct input_dev { ...@@ -1287,10 +1294,7 @@ struct input_dev {
int rep[REP_CNT]; int rep[REP_CNT];
struct input_mt_slot *mt; struct input_mt *mt;
int mtsize;
int slot;
int trkid;
struct input_absinfo *absinfo; struct input_absinfo *absinfo;
...@@ -1312,12 +1316,14 @@ struct input_dev { ...@@ -1312,12 +1316,14 @@ struct input_dev {
unsigned int users; unsigned int users;
bool going_away; bool going_away;
bool sync;
struct device dev; struct device dev;
struct list_head h_list; struct list_head h_list;
struct list_head node; struct list_head node;
unsigned int num_vals;
unsigned int max_vals;
struct input_value *vals;
}; };
#define to_input_dev(d) container_of(d, struct input_dev, dev) #define to_input_dev(d) container_of(d, struct input_dev, dev)
...@@ -1378,6 +1384,9 @@ struct input_handle; ...@@ -1378,6 +1384,9 @@ struct input_handle;
* @event: event handler. This method is being called by input core with * @event: event handler. This method is being called by input core with
* interrupts disabled and dev->event_lock spinlock held and so * interrupts disabled and dev->event_lock spinlock held and so
* it may not sleep * it may not sleep
* @events: event sequence handler. This method is being called by
* input core with interrupts disabled and dev->event_lock
* spinlock held and so it may not sleep
* @filter: similar to @event; separates normal event handlers from * @filter: similar to @event; separates normal event handlers from
* "filters". * "filters".
* @match: called after comparing device's id with handler's id_table * @match: called after comparing device's id with handler's id_table
...@@ -1387,8 +1396,8 @@ struct input_handle; ...@@ -1387,8 +1396,8 @@ struct input_handle;
* @start: starts handler for given handle. This function is called by * @start: starts handler for given handle. This function is called by
* input core right after connect() method and also when a process * input core right after connect() method and also when a process
* that "grabbed" a device releases it * that "grabbed" a device releases it
* @fops: file operations this driver implements * @legacy_minors: set to %true by drivers using legacy minor ranges
* @minor: beginning of range of 32 minors for devices this driver * @minor: beginning of range of 32 legacy minors for devices this driver
* can provide * can provide
* @name: name of the handler, to be shown in /proc/bus/input/handlers * @name: name of the handler, to be shown in /proc/bus/input/handlers
* @id_table: pointer to a table of input_device_ids this driver can * @id_table: pointer to a table of input_device_ids this driver can
...@@ -1414,13 +1423,15 @@ struct input_handler { ...@@ -1414,13 +1423,15 @@ struct input_handler {
void *private; void *private;
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
void (*events)(struct input_handle *handle,
const struct input_value *vals, unsigned int count);
bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value); bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
bool (*match)(struct input_handler *handler, struct input_dev *dev); bool (*match)(struct input_handler *handler, struct input_dev *dev);
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
void (*disconnect)(struct input_handle *handle); void (*disconnect)(struct input_handle *handle);
void (*start)(struct input_handle *handle); void (*start)(struct input_handle *handle);
const struct file_operations *fops; bool legacy_minors;
int minor; int minor;
const char *name; const char *name;
...@@ -1488,6 +1499,10 @@ void input_reset_device(struct input_dev *); ...@@ -1488,6 +1499,10 @@ void input_reset_device(struct input_dev *);
int __must_check input_register_handler(struct input_handler *); int __must_check input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *); void input_unregister_handler(struct input_handler *);
int __must_check input_get_new_minor(int legacy_base, unsigned int legacy_num,
bool allow_dynamic);
void input_free_minor(unsigned int minor);
int input_handler_for_each_handle(struct input_handler *, void *data, int input_handler_for_each_handle(struct input_handler *, void *data,
int (*fn)(struct input_handle *, void *)); int (*fn)(struct input_handle *, void *));
......
...@@ -15,12 +15,41 @@ ...@@ -15,12 +15,41 @@
#define TRKID_MAX 0xffff #define TRKID_MAX 0xffff
#define INPUT_MT_POINTER 0x0001 /* pointer device, e.g. trackpad */
#define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */
#define INPUT_MT_DROP_UNUSED 0x0004 /* drop contacts not seen in frame */
#define INPUT_MT_TRACK 0x0008 /* use in-kernel tracking */
/** /**
* struct input_mt_slot - represents the state of an input MT slot * struct input_mt_slot - represents the state of an input MT slot
* @abs: holds current values of ABS_MT axes for this slot * @abs: holds current values of ABS_MT axes for this slot
* @frame: last frame at which input_mt_report_slot_state() was called
* @key: optional driver designation of this slot
*/ */
struct input_mt_slot { struct input_mt_slot {
int abs[ABS_MT_LAST - ABS_MT_FIRST + 1]; int abs[ABS_MT_LAST - ABS_MT_FIRST + 1];
unsigned int frame;
unsigned int key;
};
/**
* struct input_mt - state of tracked contacts
* @trkid: stores MT tracking ID for the next contact
* @num_slots: number of MT slots the device uses
* @slot: MT slot currently being transmitted
* @flags: input_mt operation flags
* @frame: increases every time input_mt_sync_frame() is called
* @red: reduced cost matrix for in-kernel tracking
* @slots: array of slots holding current values of tracked contacts
*/
struct input_mt {
int trkid;
int num_slots;
int slot;
unsigned int flags;
unsigned int frame;
int *red;
struct input_mt_slot slots[];
}; };
static inline void input_mt_set_value(struct input_mt_slot *slot, static inline void input_mt_set_value(struct input_mt_slot *slot,
...@@ -35,12 +64,18 @@ static inline int input_mt_get_value(const struct input_mt_slot *slot, ...@@ -35,12 +64,18 @@ static inline int input_mt_get_value(const struct input_mt_slot *slot,
return slot->abs[code - ABS_MT_FIRST]; return slot->abs[code - ABS_MT_FIRST];
} }
int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots); static inline bool input_mt_is_active(const struct input_mt_slot *slot)
{
return input_mt_get_value(slot, ABS_MT_TRACKING_ID) >= 0;
}
int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
unsigned int flags);
void input_mt_destroy_slots(struct input_dev *dev); void input_mt_destroy_slots(struct input_dev *dev);
static inline int input_mt_new_trkid(struct input_dev *dev) static inline int input_mt_new_trkid(struct input_mt *mt)
{ {
return dev->trkid++ & TRKID_MAX; return mt->trkid++ & TRKID_MAX;
} }
static inline void input_mt_slot(struct input_dev *dev, int slot) static inline void input_mt_slot(struct input_dev *dev, int slot)
...@@ -64,4 +99,20 @@ void input_mt_report_slot_state(struct input_dev *dev, ...@@ -64,4 +99,20 @@ void input_mt_report_slot_state(struct input_dev *dev,
void input_mt_report_finger_count(struct input_dev *dev, int count); void input_mt_report_finger_count(struct input_dev *dev, int count);
void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count); void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count);
void input_mt_sync_frame(struct input_dev *dev);
/**
* struct input_mt_pos - contact position
* @x: horizontal coordinate
* @y: vertical coordinate
*/
struct input_mt_pos {
s16 x, y;
};
int input_mt_assign_slots(struct input_dev *dev, int *slots,
const struct input_mt_pos *pos, int num_pos);
int input_mt_get_slot_by_key(struct input_dev *dev, int key);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment