]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'for-next' of git://github.com/rydberg/linux into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Mon, 1 Oct 2012 21:40:51 +0000 (14:40 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Mon, 1 Oct 2012 21:40:51 +0000 (14:40 -0700)
Merge Henrik's updates to multitouch code. Even though Jiri already
pulled them in I need to do it too since my changes to evdev using
dynamic major would clash with them.

25 files changed:
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-magicmouse.c
drivers/hid/hid-multitouch.c
drivers/input/evdev.c
drivers/input/input-mt.c
drivers/input/input.c
drivers/input/misc/uinput.c
drivers/input/mouse/alps.c
drivers/input/mouse/bcm5974.c
drivers/input/mouse/elantech.c
drivers/input/mouse/sentelic.c
drivers/input/mouse/synaptics.c
drivers/input/tablet/wacom_wac.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/cyttsp_core.c
drivers/input/touchscreen/edt-ft5x06.c
drivers/input/touchscreen/egalax_ts.c
drivers/input/touchscreen/ili210x.c
drivers/input/touchscreen/mms114.c
drivers/input/touchscreen/penmount.c
drivers/input/touchscreen/wacom_w8001.c
include/linux/hid.h
include/linux/input.h
include/linux/input/mt.h

index 1dcb76ff51e340a2215d735bdde23e5c370bade0..c843db9e283f3921ee874a1199b0c9b29b84131b 100644 (file)
 #define USB_VENDOR_ID_EMS              0x2006
 #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_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
index 811bfad64609313614ae935337290ef4af21d999..d917c0d536856c80b7b898c7ad950b4728c16db6 100644 (file)
@@ -1154,6 +1154,7 @@ static void report_features(struct hid_device *hid)
 
 int hidinput_connect(struct hid_device *hid, unsigned int force)
 {
+       struct hid_driver *drv = hid->driver;
        struct hid_report *report;
        struct hid_input *hidinput = NULL;
        struct input_dev *input_dev;
@@ -1228,6 +1229,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
                                 * UGCI) cram a lot of unrelated inputs into the
                                 * same interface. */
                                hidinput->report = report;
+                               if (drv->input_configured)
+                                       drv->input_configured(hid, hidinput);
                                if (input_register_device(hidinput->input))
                                        goto out_cleanup;
                                hidinput = NULL;
@@ -1235,8 +1238,12 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
                }
        }
 
-       if (hidinput && input_register_device(hidinput->input))
-               goto out_cleanup;
+       if (hidinput) {
+               if (drv->input_configured)
+                       drv->input_configured(hid, hidinput);
+               if (input_register_device(hidinput->input))
+                       goto out_cleanup;
+       }
 
        return 0;
 
index 73647266daadc57ecd36a948e50ff6df80aeed21..25ddf3e3aec641fd4d883843e87e59bc0e3b0c51 100644 (file)
@@ -392,7 +392,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
 
        __set_bit(EV_ABS, input->evbit);
 
-       error = input_mt_init_slots(input, 16);
+       error = input_mt_init_slots(input, 16, 0);
        if (error)
                return error;
        input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2,
index 59c8b5c1d2de62b9a1d5a910dfa7f3ad5e470c51..ee0b76b398cb5a6a6fcda16dedbadff404d8f643 100644 (file)
@@ -51,12 +51,12 @@ MODULE_LICENSE("GPL");
 #define MT_QUIRK_VALID_IS_INRANGE      (1 << 5)
 #define MT_QUIRK_VALID_IS_CONFIDENCE   (1 << 6)
 #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE   (1 << 8)
+#define MT_QUIRK_NO_AREA               (1 << 9)
 
 struct mt_slot {
        __s32 x, y, p, w, h;
        __s32 contactid;        /* the device ContactID assigned to this slot */
        bool touch_state;       /* is the touch valid? */
-       bool seen_in_this_frame;/* has this slot been updated */
 };
 
 struct mt_class {
@@ -92,8 +92,9 @@ struct mt_device {
        __u8 touches_by_report; /* how many touches are present in one report:
                                * 1 means we should use a serial protocol
                                * > 1 means hybrid (multitouch) protocol */
+       bool serial_maybe;      /* need to check for serial protocol */
        bool curvalid;          /* is the current contact valid? */
-       struct mt_slot *slots;
+       unsigned mt_flags;      /* flags to pass to input-mt */
 };
 
 /* classes of device behavior */
@@ -115,6 +116,7 @@ struct mt_device {
 #define MT_CLS_EGALAX_SERIAL                   0x0104
 #define MT_CLS_TOPSEED                         0x0105
 #define MT_CLS_PANASONIC                       0x0106
+#define MT_CLS_FLATFROG                                0x0107
 
 #define MT_DEFAULT_MAXCONTACT  10
 
@@ -134,25 +136,6 @@ static int cypress_compute_slot(struct mt_device *td)
                return -1;
 }
 
-static int find_slot_from_contactid(struct mt_device *td)
-{
-       int i;
-       for (i = 0; i < td->maxcontacts; ++i) {
-               if (td->slots[i].contactid == td->curdata.contactid &&
-                       td->slots[i].touch_state)
-                       return i;
-       }
-       for (i = 0; i < td->maxcontacts; ++i) {
-               if (!td->slots[i].seen_in_this_frame &&
-                       !td->slots[i].touch_state)
-                       return i;
-       }
-       /* should not occurs. If this happens that means
-        * that the device sent more touches that it says
-        * in the report descriptor. It is ignored then. */
-       return -1;
-}
-
 static struct mt_class mt_classes[] = {
        { .name = MT_CLS_DEFAULT,
                .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
@@ -190,7 +173,9 @@ static struct mt_class mt_classes[] = {
                        MT_QUIRK_SLOT_IS_CONTACTID,
                .sn_move = 2048,
                .sn_width = 128,
-               .sn_height = 128 },
+               .sn_height = 128,
+               .maxcontacts = 60,
+       },
        { .name = MT_CLS_CYPRESS,
                .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
                        MT_QUIRK_CYPRESS,
@@ -216,6 +201,12 @@ static struct mt_class mt_classes[] = {
                .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP,
                .maxcontacts = 4 },
 
+       { .name = MT_CLS_FLATFROG,
+               .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
+                       MT_QUIRK_NO_AREA,
+               .sn_move = 2048,
+               .maxcontacts = 40,
+       },
        { }
 };
 
@@ -319,24 +310,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        * We need to ignore fields that belong to other collections
        * such as Mouse that might have the same GenericDesktop usages. */
        if (field->application == HID_DG_TOUCHSCREEN)
-               set_bit(INPUT_PROP_DIRECT, hi->input->propbit);
+               td->mt_flags |= INPUT_MT_DIRECT;
        else if (field->application != HID_DG_TOUCHPAD)
                return 0;
 
-       /* In case of an indirect device (touchpad), we need to add
-        * specific BTN_TOOL_* to be handled by the synaptics xorg
-        * driver.
-        * We also consider that touchscreens providing buttons are touchpads.
+       /*
+        * Model touchscreens providing buttons as touchpads.
         */
        if (field->application == HID_DG_TOUCHPAD ||
-           (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON ||
-           cls->is_indirect) {
-               set_bit(INPUT_PROP_POINTER, hi->input->propbit);
-               set_bit(BTN_TOOL_FINGER, hi->input->keybit);
-               set_bit(BTN_TOOL_DOUBLETAP, hi->input->keybit);
-               set_bit(BTN_TOOL_TRIPLETAP, hi->input->keybit);
-               set_bit(BTN_TOOL_QUADTAP, hi->input->keybit);
-       }
+           (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
+               td->mt_flags |= INPUT_MT_POINTER;
 
        /* eGalax devices provide a Digitizer.Stylus input which overrides
         * the correct Digitizers.Finger X/Y ranges.
@@ -353,8 +336,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                                        EV_ABS, ABS_MT_POSITION_X);
                        set_abs(hi->input, ABS_MT_POSITION_X, field,
                                cls->sn_move);
-                       /* touchscreen emulation */
-                       set_abs(hi->input, ABS_X, field, cls->sn_move);
                        mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
@@ -363,8 +344,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                                        EV_ABS, ABS_MT_POSITION_Y);
                        set_abs(hi->input, ABS_MT_POSITION_Y, field,
                                cls->sn_move);
-                       /* touchscreen emulation */
-                       set_abs(hi->input, ABS_Y, field, cls->sn_move);
                        mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
@@ -388,9 +367,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        td->last_field_index = field->index;
                        return 1;
                case HID_DG_CONTACTID:
-                       if (!td->maxcontacts)
-                               td->maxcontacts = MT_DEFAULT_MAXCONTACT;
-                       input_mt_init_slots(hi->input, td->maxcontacts);
                        mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        td->touches_by_report++;
@@ -398,18 +374,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                case HID_DG_WIDTH:
                        hid_map_usage(hi, usage, bit, max,
                                        EV_ABS, ABS_MT_TOUCH_MAJOR);
-                       set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
-                               cls->sn_width);
+                       if (!(cls->quirks & MT_QUIRK_NO_AREA))
+                               set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
+                                       cls->sn_width);
                        mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
                case HID_DG_HEIGHT:
                        hid_map_usage(hi, usage, bit, max,
                                        EV_ABS, ABS_MT_TOUCH_MINOR);
-                       set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
-                               cls->sn_height);
-                       input_set_abs_params(hi->input,
+                       if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
+                               set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
+                                       cls->sn_height);
+                               input_set_abs_params(hi->input,
                                        ABS_MT_ORIENTATION, 0, 1, 0, 0);
+                       }
                        mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
@@ -418,9 +397,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                                        EV_ABS, ABS_MT_PRESSURE);
                        set_abs(hi->input, ABS_MT_PRESSURE, field,
                                cls->sn_pressure);
-                       /* touchscreen emulation */
-                       set_abs(hi->input, ABS_PRESSURE, field,
-                               cls->sn_pressure);
                        mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
@@ -464,7 +440,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
        return -1;
 }
 
-static int mt_compute_slot(struct mt_device *td)
+static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
 {
        __s32 quirks = td->mtclass.quirks;
 
@@ -480,42 +456,23 @@ static int mt_compute_slot(struct mt_device *td)
        if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
                return td->curdata.contactid - 1;
 
-       return find_slot_from_contactid(td);
+       return input_mt_get_slot_by_key(input, td->curdata.contactid);
 }
 
 /*
  * this function is called when a whole contact has been processed,
  * so that it can assign it to a slot and store the data there
  */
-static void mt_complete_slot(struct mt_device *td)
+static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
 {
-       td->curdata.seen_in_this_frame = true;
        if (td->curvalid) {
-               int slotnum = mt_compute_slot(td);
-
-               if (slotnum >= 0 && slotnum < td->maxcontacts)
-                       td->slots[slotnum] = td->curdata;
-       }
-       td->num_received++;
-}
-
+               int slotnum = mt_compute_slot(td, input);
+               struct mt_slot *s = &td->curdata;
 
-/*
- * this function is called when a whole packet has been received and processed,
- * so that it can decide what to send to the input layer.
- */
-static void mt_emit_event(struct mt_device *td, struct input_dev *input)
-{
-       int i;
+               if (slotnum < 0 || slotnum >= td->maxcontacts)
+                       return;
 
-       for (i = 0; i < td->maxcontacts; ++i) {
-               struct mt_slot *s = &(td->slots[i]);
-               if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) &&
-                       !s->seen_in_this_frame) {
-                       s->touch_state = false;
-               }
-
-               input_mt_slot(input, i);
+               input_mt_slot(input, slotnum);
                input_mt_report_slot_state(input, MT_TOOL_FINGER,
                        s->touch_state);
                if (s->touch_state) {
@@ -532,24 +489,29 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input)
                        input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
                        input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
                }
-               s->seen_in_this_frame = false;
-
        }
 
-       input_mt_report_pointer_emulation(input, true);
+       td->num_received++;
+}
+
+/*
+ * this function is called when a whole packet has been received and processed,
+ * so that it can decide what to send to the input layer.
+ */
+static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
+{
+       input_mt_sync_frame(input);
        input_sync(input);
        td->num_received = 0;
 }
 
-
-
 static int mt_event(struct hid_device *hid, struct hid_field *field,
                                struct hid_usage *usage, __s32 value)
 {
        struct mt_device *td = hid_get_drvdata(hid);
        __s32 quirks = td->mtclass.quirks;
 
-       if (hid->claimed & HID_CLAIMED_INPUT && td->slots) {
+       if (hid->claimed & HID_CLAIMED_INPUT) {
                switch (usage->hid) {
                case HID_DG_INRANGE:
                        if (quirks & MT_QUIRK_ALWAYS_VALID)
@@ -602,11 +564,11 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
                }
 
                if (usage->hid == td->last_slot_field)
-                       mt_complete_slot(td);
+                       mt_complete_slot(td, field->hidinput->input);
 
                if (field->index == td->last_field_index
                        && td->num_received >= td->num_expected)
-                       mt_emit_event(td, field->hidinput->input);
+                       mt_sync_frame(td, field->hidinput->input);
 
        }
 
@@ -685,6 +647,35 @@ static void mt_post_parse(struct mt_device *td)
        }
 }
 
+static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
+
+{
+       struct mt_device *td = hid_get_drvdata(hdev);
+       struct mt_class *cls = &td->mtclass;
+       struct input_dev *input = hi->input;
+
+       /* Only initialize slots for MT input devices */
+       if (!test_bit(ABS_MT_POSITION_X, input->absbit))
+               return;
+
+       if (!td->maxcontacts)
+               td->maxcontacts = MT_DEFAULT_MAXCONTACT;
+
+       mt_post_parse(td);
+       if (td->serial_maybe)
+               mt_post_parse_default_settings(td);
+
+       if (cls->is_indirect)
+               td->mt_flags |= INPUT_MT_POINTER;
+
+       if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
+               td->mt_flags |= INPUT_MT_DROP_UNUSED;
+
+       input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
+
+       td->mt_flags = 0;
+}
+
 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        int ret, i;
@@ -722,6 +713,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
                goto fail;
        }
 
+       if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
+               td->serial_maybe = true;
+
        ret = hid_parse(hdev);
        if (ret != 0)
                goto fail;
@@ -730,20 +724,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (ret)
                goto fail;
 
-       mt_post_parse(td);
-
-       if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
-               mt_post_parse_default_settings(td);
-
-       td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
-                               GFP_KERNEL);
-       if (!td->slots) {
-               dev_err(&hdev->dev, "cannot allocate multitouch slots\n");
-               hid_hw_stop(hdev);
-               ret = -ENOMEM;
-               goto fail;
-       }
-
        ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
 
        mt_set_maxcontacts(hdev);
@@ -774,7 +754,6 @@ static void mt_remove(struct hid_device *hdev)
        struct mt_device *td = hid_get_drvdata(hdev);
        sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
        hid_hw_stop(hdev);
-       kfree(td->slots);
        kfree(td);
        hid_set_drvdata(hdev, NULL);
 }
@@ -892,6 +871,11 @@ static const struct hid_device_id mt_devices[] = {
                MT_USB_DEVICE(USB_VENDOR_ID_ELO,
                        USB_DEVICE_ID_ELO_TS2515) },
 
+       /* Flatfrog Panels */
+       { .driver_data = MT_CLS_FLATFROG,
+               MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG,
+                       USB_DEVICE_ID_MULTITOUCH_3200) },
+
        /* GeneralTouch panel */
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
                MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
@@ -1087,6 +1071,7 @@ static struct hid_driver mt_driver = {
        .remove = mt_remove,
        .input_mapping = mt_input_mapping,
        .input_mapped = mt_input_mapped,
+       .input_configured = mt_input_configured,
        .feature_mapping = mt_feature_mapping,
        .usage_table = mt_grabbed_usages,
        .event = mt_event,
index 6c58bfff01a3446b8dee0d7d51eeff1f98fbe2aa..118d0300f1fb72a1324006f544b790a6085affa2 100644 (file)
@@ -54,16 +54,9 @@ struct evdev_client {
 static struct evdev *evdev_table[EVDEV_MINORS];
 static DEFINE_MUTEX(evdev_table_mutex);
 
-static void evdev_pass_event(struct evdev_client *client,
-                            struct input_event *event,
-                            ktime_t mono, ktime_t real)
+static void __pass_event(struct evdev_client *client,
+                        const struct input_event *event)
 {
-       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->head &= client->bufsize - 1;
 
@@ -86,42 +79,74 @@ static void evdev_pass_event(struct evdev_client *client,
                client->packet_head = client->head;
                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);
+
+       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,
-                       unsigned int type, unsigned int code, int value)
+static void evdev_events(struct input_handle *handle,
+                        const struct input_value *vals, unsigned int count)
 {
        struct evdev *evdev = handle->private;
        struct evdev_client *client;
-       struct input_event event;
        ktime_t time_mono, time_real;
 
        time_mono = ktime_get();
        time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
 
-       event.type = type;
-       event.code = code;
-       event.value = value;
-
        rcu_read_lock();
 
        client = rcu_dereference(evdev->grab);
 
        if (client)
-               evdev_pass_event(client, &event, time_mono, time_real);
+               evdev_pass_values(client, vals, count, time_mono, time_real);
        else
                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();
+}
 
-       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)
@@ -653,20 +678,22 @@ static int evdev_handle_mt_request(struct input_dev *dev,
                                   unsigned int size,
                                   int __user *ip)
 {
-       const struct input_mt_slot *mt = dev->mt;
+       const struct input_mt *mt = dev->mt;
        unsigned int code;
        int max_slots;
        int i;
 
        if (get_user(code, &ip[0]))
                return -EFAULT;
-       if (!input_is_mt_value(code))
+       if (!mt || !input_is_mt_value(code))
                return -EINVAL;
 
        max_slots = (size - sizeof(__u32)) / sizeof(__s32);
-       for (i = 0; i < dev->mtsize && i < max_slots; i++)
-               if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i]))
+       for (i = 0; i < mt->num_slots && i < max_slots; i++) {
+               int value = input_mt_get_value(&mt->slots[i], code);
+               if (put_user(value, &ip[1 + i]))
                        return -EFAULT;
+       }
 
        return 0;
 }
@@ -1048,6 +1075,7 @@ MODULE_DEVICE_TABLE(input, evdev_ids);
 
 static struct input_handler evdev_handler = {
        .event          = evdev_event,
+       .events         = evdev_events,
        .connect        = evdev_connect,
        .disconnect     = evdev_disconnect,
        .fops           = &evdev_fops,
index 70a16c7da8ccbefc542477e27623a8641c72ad25..c0ec7d42c3be05ffd574daec1870d44d560ed15a 100644 (file)
 
 #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
  * @dev: input device supporting MT events and finger tracking
  * May be called repeatedly. Returns -EINVAL if attempting to
  * 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;
 
        if (!num_slots)
                return 0;
-       if (dev->mt)
-               return dev->mtsize != num_slots ? -EINVAL : 0;
+       if (mt)
+               return mt->num_slots != num_slots ? -EINVAL : 0;
 
-       dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
-       if (!dev->mt)
-               return -ENOMEM;
+       mt = kzalloc(sizeof(*mt) + num_slots * sizeof(*mt->slots), GFP_KERNEL);
+       if (!mt)
+               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_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' */
        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;
+err_mem:
+       kfree(mt);
+       return -ENOMEM;
 }
 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)
 {
-       kfree(dev->mt);
+       if (dev->mt) {
+               kfree(dev->mt->red);
+               kfree(dev->mt);
+       }
        dev->mt = NULL;
-       dev->mtsize = 0;
-       dev->slot = 0;
-       dev->trkid = 0;
 }
 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,
                                unsigned int tool_type, bool active)
 {
-       struct input_mt_slot *mt;
+       struct input_mt *mt = dev->mt;
+       struct input_mt_slot *slot;
        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);
                return;
        }
 
-       mt = &dev->mt[dev->slot];
-       id = input_mt_get_value(mt, ABS_MT_TRACKING_ID);
-       if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type)
-               id = input_mt_new_trkid(dev);
+       id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
+       if (id < 0 || input_mt_get_value(slot, ABS_MT_TOOL_TYPE) != tool_type)
+               id = input_mt_new_trkid(mt);
 
        input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
        input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
@@ -135,13 +183,19 @@ EXPORT_SYMBOL(input_mt_report_finger_count);
  */
 void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
 {
-       struct input_mt_slot *oldest = NULL;
-       int oldid = dev->trkid;
-       int count = 0;
-       int i;
+       struct input_mt *mt = dev->mt;
+       struct input_mt_slot *oldest;
+       int oldid, count, i;
+
+       if (!mt)
+               return;
+
+       oldest = 0;
+       oldid = mt->trkid;
+       count = 0;
 
-       for (i = 0; i < dev->mtsize; ++i) {
-               struct input_mt_slot *ps = &dev->mt[i];
+       for (i = 0; i < mt->num_slots; ++i) {
+               struct input_mt_slot *ps = &mt->slots[i];
                int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
 
                if (id < 0)
@@ -160,13 +214,208 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
        if (oldest) {
                int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
                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_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 {
-               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);
+
+/**
+ * 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);
index 768e46b05ef03eb6066a3a03ec0058938bcfc612..ace3f7c4226d60325fb11b1959fae61180cb3869 100644 (file)
@@ -47,6 +47,8 @@ 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,
                                     unsigned long *bm, unsigned int max)
 {
@@ -69,42 +71,102 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
        return value;
 }
 
+static void input_start_autorepeat(struct input_dev *dev, int code)
+{
+       if (test_bit(EV_REP, dev->evbit) &&
+           dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
+           dev->timer.data) {
+               dev->repeat_key = code;
+               mod_timer(&dev->timer,
+                         jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
+       }
+}
+
+static void input_stop_autorepeat(struct input_dev *dev)
+{
+       del_timer(&dev->timer);
+}
+
 /*
  * Pass event first through all filters and then, if event has not been
  * filtered out, through all open handles. This function is called with
  * dev->event_lock held and interrupts disabled.
  */
-static void input_pass_event(struct input_dev *dev,
-                            unsigned int type, unsigned int code, int value)
+static unsigned int input_to_handler(struct input_handle *handle,
+                       struct input_value *vals, unsigned int count)
+{
+       struct input_handler *handler = handle->handler;
+       struct input_value *end = vals;
+       struct input_value *v;
+
+       for (v = vals; v != vals + count; v++) {
+               if (handler->filter &&
+                   handler->filter(handle, v->type, v->code, v->value))
+                       continue;
+               if (end != v)
+                       *end = *v;
+               end++;
+       }
+
+       count = end - vals;
+       if (!count)
+               return 0;
+
+       if (handler->events)
+               handler->events(handle, vals, count);
+       else if (handler->event)
+               for (v = vals; v != end; v++)
+                       handler->event(handle, v->type, v->code, v->value);
+
+       return count;
+}
+
+/*
+ * Pass values first through all filters and then, if event has not been
+ * filtered out, through all open handles. This function is called with
+ * dev->event_lock held and interrupts disabled.
+ */
+static void input_pass_values(struct input_dev *dev,
+                             struct input_value *vals, unsigned int count)
 {
-       struct input_handler *handler;
        struct input_handle *handle;
+       struct input_value *v;
+
+       if (!count)
+               return;
 
        rcu_read_lock();
 
        handle = rcu_dereference(dev->grab);
-       if (handle)
-               handle->handler->event(handle, type, code, value);
-       else {
-               bool filtered = false;
-
-               list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
-                       if (!handle->open)
-                               continue;
+       if (handle) {
+               count = input_to_handler(handle, vals, count);
+       } else {
+               list_for_each_entry_rcu(handle, &dev->h_list, d_node)
+                       if (handle->open)
+                               count = input_to_handler(handle, vals, count);
+       }
 
-                       handler = handle->handler;
-                       if (!handler->filter) {
-                               if (filtered)
-                                       break;
+       rcu_read_unlock();
 
-                               handler->event(handle, type, code, value);
+       add_input_randomness(vals->type, vals->code, vals->value);
 
-                       } else if (handler->filter(handle, type, code, value))
-                               filtered = true;
+       /* trigger auto repeat for key events */
+       for (v = vals; v != vals + count; v++) {
+               if (v->type == EV_KEY && v->value != 2) {
+                       if (v->value)
+                               input_start_autorepeat(dev, v->code);
+                       else
+                               input_stop_autorepeat(dev);
                }
        }
+}
 
-       rcu_read_unlock();
+static void input_pass_event(struct input_dev *dev,
+                            unsigned int type, unsigned int code, int value)
+{
+       struct input_value vals[] = { { type, code, value } };
+
+       input_pass_values(dev, vals, ARRAY_SIZE(vals));
 }
 
 /*
@@ -121,18 +183,12 @@ static void input_repeat_key(unsigned long data)
 
        if (test_bit(dev->repeat_key, dev->key) &&
            is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
+               struct input_value vals[] =  {
+                       { EV_KEY, dev->repeat_key, 2 },
+                       input_value_sync
+               };
 
-               input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
-
-               if (dev->sync) {
-                       /*
-                        * Only send SYN_REPORT if we are not in a middle
-                        * of driver parsing a new hardware packet.
-                        * Otherwise assume that the driver will send
-                        * SYN_REPORT once it's done.
-                        */
-                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
-               }
+               input_pass_values(dev, vals, ARRAY_SIZE(vals));
 
                if (dev->rep[REP_PERIOD])
                        mod_timer(&dev->timer, jiffies +
@@ -142,30 +198,17 @@ static void input_repeat_key(unsigned long data)
        spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
-static void input_start_autorepeat(struct input_dev *dev, int code)
-{
-       if (test_bit(EV_REP, dev->evbit) &&
-           dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
-           dev->timer.data) {
-               dev->repeat_key = code;
-               mod_timer(&dev->timer,
-                         jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
-       }
-}
-
-static void input_stop_autorepeat(struct input_dev *dev)
-{
-       del_timer(&dev->timer);
-}
-
 #define INPUT_IGNORE_EVENT     0
 #define INPUT_PASS_TO_HANDLERS 1
 #define INPUT_PASS_TO_DEVICE   2
+#define INPUT_SLOT             4
+#define INPUT_FLUSH            8
 #define INPUT_PASS_TO_ALL      (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
 static int input_handle_abs_event(struct input_dev *dev,
                                  unsigned int code, int *pval)
 {
+       struct input_mt *mt = dev->mt;
        bool is_mt_event;
        int *pold;
 
@@ -174,8 +217,8 @@ static int input_handle_abs_event(struct input_dev *dev,
                 * "Stage" the event; we'll flush it later, when we
                 * get actual touch data.
                 */
-               if (*pval >= 0 && *pval < dev->mtsize)
-                       dev->slot = *pval;
+               if (mt && *pval >= 0 && *pval < mt->num_slots)
+                       mt->slot = *pval;
 
                return INPUT_IGNORE_EVENT;
        }
@@ -184,9 +227,8 @@ static int input_handle_abs_event(struct input_dev *dev,
 
        if (!is_mt_event) {
                pold = &dev->absinfo[code].value;
-       } else if (dev->mt) {
-               struct input_mt_slot *mtslot = &dev->mt[dev->slot];
-               pold = &mtslot->abs[code - ABS_MT_FIRST];
+       } else if (mt) {
+               pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST];
        } else {
                /*
                 * Bypass filtering for multi-touch events when
@@ -205,16 +247,16 @@ static int input_handle_abs_event(struct input_dev *dev,
        }
 
        /* Flush pending "slot" event */
-       if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
-               input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
-               input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
+       if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
+               input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);
+               return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;
        }
 
        return INPUT_PASS_TO_HANDLERS;
 }
 
-static void input_handle_event(struct input_dev *dev,
-                              unsigned int type, unsigned int code, int value)
+static int input_get_disposition(struct input_dev *dev,
+                         unsigned int type, unsigned int code, int value)
 {
        int disposition = INPUT_IGNORE_EVENT;
 
@@ -227,37 +269,34 @@ static void input_handle_event(struct input_dev *dev,
                        break;
 
                case SYN_REPORT:
-                       if (!dev->sync) {
-                               dev->sync = true;
-                               disposition = INPUT_PASS_TO_HANDLERS;
-                       }
+                       disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH;
                        break;
                case SYN_MT_REPORT:
-                       dev->sync = false;
                        disposition = INPUT_PASS_TO_HANDLERS;
                        break;
                }
                break;
 
        case EV_KEY:
-               if (is_event_supported(code, dev->keybit, KEY_MAX) &&
-                   !!test_bit(code, dev->key) != value) {
+               if (is_event_supported(code, dev->keybit, KEY_MAX)) {
 
-                       if (value != 2) {
-                               __change_bit(code, dev->key);
-                               if (value)
-                                       input_start_autorepeat(dev, code);
-                               else
-                                       input_stop_autorepeat(dev);
+                       /* auto-repeat bypasses state updates */
+                       if (value == 2) {
+                               disposition = INPUT_PASS_TO_HANDLERS;
+                               break;
                        }
 
-                       disposition = INPUT_PASS_TO_HANDLERS;
+                       if (!!test_bit(code, dev->key) != !!value) {
+
+                               __change_bit(code, dev->key);
+                               disposition = INPUT_PASS_TO_HANDLERS;
+                       }
                }
                break;
 
        case EV_SW:
                if (is_event_supported(code, dev->swbit, SW_MAX) &&
-                   !!test_bit(code, dev->sw) != value) {
+                   !!test_bit(code, dev->sw) != !!value) {
 
                        __change_bit(code, dev->sw);
                        disposition = INPUT_PASS_TO_HANDLERS;
@@ -284,7 +323,7 @@ static void input_handle_event(struct input_dev *dev,
 
        case EV_LED:
                if (is_event_supported(code, dev->ledbit, LED_MAX) &&
-                   !!test_bit(code, dev->led) != value) {
+                   !!test_bit(code, dev->led) != !!value) {
 
                        __change_bit(code, dev->led);
                        disposition = INPUT_PASS_TO_ALL;
@@ -317,14 +356,48 @@ static void input_handle_event(struct input_dev *dev,
                break;
        }
 
-       if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
-               dev->sync = false;
+       return disposition;
+}
+
+static void input_handle_event(struct input_dev *dev,
+                              unsigned int type, unsigned int code, int value)
+{
+       int disposition;
+
+       disposition = input_get_disposition(dev, type, code, value);
 
        if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
                dev->event(dev, type, code, value);
 
-       if (disposition & INPUT_PASS_TO_HANDLERS)
-               input_pass_event(dev, type, code, value);
+       if (!dev->vals)
+               return;
+
+       if (disposition & INPUT_PASS_TO_HANDLERS) {
+               struct input_value *v;
+
+               if (disposition & INPUT_SLOT) {
+                       v = &dev->vals[dev->num_vals++];
+                       v->type = EV_ABS;
+                       v->code = ABS_MT_SLOT;
+                       v->value = dev->mt->slot;
+               }
+
+               v = &dev->vals[dev->num_vals++];
+               v->type = type;
+               v->code = code;
+               v->value = value;
+       }
+
+       if (disposition & INPUT_FLUSH) {
+               if (dev->num_vals >= 2)
+                       input_pass_values(dev, dev->vals, dev->num_vals);
+               dev->num_vals = 0;
+       } else if (dev->num_vals >= dev->max_vals - 2) {
+               dev->vals[dev->num_vals++] = input_value_sync;
+               input_pass_values(dev, dev->vals, dev->num_vals);
+               dev->num_vals = 0;
+       }
+
 }
 
 /**
@@ -352,7 +425,6 @@ void input_event(struct input_dev *dev,
        if (is_event_supported(type, dev->evbit, EV_MAX)) {
 
                spin_lock_irqsave(&dev->event_lock, flags);
-               add_input_randomness(type, code, value);
                input_handle_event(dev, type, code, value);
                spin_unlock_irqrestore(&dev->event_lock, flags);
        }
@@ -831,10 +903,12 @@ int input_set_keycode(struct input_dev *dev,
        if (test_bit(EV_KEY, dev->evbit) &&
            !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
            __test_and_clear_bit(old_keycode, dev->key)) {
+               struct input_value vals[] =  {
+                       { EV_KEY, old_keycode, 0 },
+                       input_value_sync
+               };
 
-               input_pass_event(dev, EV_KEY, old_keycode, 0);
-               if (dev->sync)
-                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+               input_pass_values(dev, vals, ARRAY_SIZE(vals));
        }
 
  out:
@@ -1425,6 +1499,7 @@ static void input_dev_release(struct device *device)
        input_ff_destroy(dev);
        input_mt_destroy_slots(dev);
        kfree(dev->absinfo);
+       kfree(dev->vals);
        kfree(dev);
 
        module_put(THIS_MODULE);
@@ -1760,8 +1835,8 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
        int i;
        unsigned int events;
 
-       if (dev->mtsize) {
-               mt_slots = dev->mtsize;
+       if (dev->mt) {
+               mt_slots = dev->mt->num_slots;
        } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) {
                mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum -
                           dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1,
@@ -1787,6 +1862,9 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
                if (test_bit(i, dev->relbit))
                        events++;
 
+       /* Make room for KEY and MSC events */
+       events += 7;
+
        return events;
 }
 
@@ -1825,6 +1903,7 @@ int input_register_device(struct input_dev *dev)
 {
        static atomic_t input_no = ATOMIC_INIT(0);
        struct input_handler *handler;
+       unsigned int packet_size;
        const char *path;
        int error;
 
@@ -1837,9 +1916,14 @@ int input_register_device(struct input_dev *dev)
        /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
        input_cleanse_bitmasks(dev);
 
-       if (!dev->hint_events_per_packet)
-               dev->hint_events_per_packet =
-                               input_estimate_events_per_packet(dev);
+       packet_size = input_estimate_events_per_packet(dev);
+       if (dev->hint_events_per_packet < packet_size)
+               dev->hint_events_per_packet = packet_size;
+
+       dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2;
+       dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
+       if (!dev->vals)
+               return -ENOMEM;
 
        /*
         * If delay and period are pre-set by the driver, then autorepeating
index 86328e9c98489dc890a665260f718fa13cab2d07..a0a4bbaef02c242a8ee16e54bdb9337e8f80407e 100644 (file)
@@ -416,7 +416,7 @@ static int uinput_setup_device(struct uinput_device *udev,
                        goto exit;
                if (test_bit(ABS_MT_SLOT, dev->absbit)) {
                        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)) {
                        input_set_events_per_packet(dev, 60);
                }
index 4a1347e91bdcae3a72562b0f966b0025b5afec21..cf5af1f495ec5351125b43ee71ce725cc4644b21 100644 (file)
@@ -1620,7 +1620,7 @@ int alps_init(struct psmouse *psmouse)
        case ALPS_PROTO_V3:
        case ALPS_PROTO_V4:
                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_Y, 0, ALPS_V3_Y_MAX, 0, 0);
 
index d528c23e194f6efcbe7efbe8651d218aa6ef7965..3a78f235fa3e70b8057b929a2c4e2e763141cd9f 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/usb/input.h>
 #include <linux/hid.h>
 #include <linux/mutex.h>
+#include <linux/input/mt.h>
 
 #define USB_VENDOR_ID_APPLE            0x05ac
 
@@ -183,26 +184,26 @@ struct tp_finger {
        __le16 abs_y;           /* absolute y coodinate */
        __le16 rel_x;           /* relative x coodinate */
        __le16 rel_y;           /* relative y coodinate */
-       __le16 size_major;      /* finger size, major axis? */
-       __le16 size_minor;      /* finger size, minor axis? */
+       __le16 tool_major;      /* tool area, major axis */
+       __le16 tool_minor;      /* tool area, minor axis */
        __le16 orientation;     /* 16384 when point, else 15 bit angle */
-       __le16 force_major;     /* trackpad force, major axis? */
-       __le16 force_minor;     /* trackpad force, minor axis? */
+       __le16 touch_major;     /* touch area, major axis */
+       __le16 touch_minor;     /* touch area, minor axis */
        __le16 unused[3];       /* zeros */
        __le16 multi;           /* one finger: varies, more fingers: constant */
 } __attribute__((packed,aligned(2)));
 
 /* trackpad finger data size, empirically at least ten fingers */
+#define MAX_FINGERS            16
 #define SIZEOF_FINGER          sizeof(struct tp_finger)
-#define SIZEOF_ALL_FINGERS     (16 * SIZEOF_FINGER)
+#define SIZEOF_ALL_FINGERS     (MAX_FINGERS * SIZEOF_FINGER)
 #define MAX_FINGER_ORIENTATION 16384
 
 /* device-specific parameters */
 struct bcm5974_param {
-       int dim;                /* logical dimension */
-       int fuzz;               /* logical noise value */
-       int devmin;             /* device minimum reading */
-       int devmax;             /* device maximum reading */
+       int snratio;            /* signal-to-noise ratio */
+       int min;                /* device minimum reading */
+       int max;                /* device maximum reading */
 };
 
 /* device-specific configuration */
@@ -219,6 +220,7 @@ struct bcm5974_config {
        struct bcm5974_param w; /* finger width limits */
        struct bcm5974_param x; /* horizontal limits */
        struct bcm5974_param y; /* vertical limits */
+       struct bcm5974_param o; /* orientation limits */
 };
 
 /* logical device structure */
@@ -234,23 +236,16 @@ struct bcm5974 {
        struct bt_data *bt_data;        /* button transferred data */
        struct urb *tp_urb;             /* trackpad usb request block */
        u8 *tp_data;                    /* trackpad transferred data */
-       int fingers;                    /* number of fingers on trackpad */
+       const struct tp_finger *index[MAX_FINGERS];     /* finger index data */
+       struct input_mt_pos pos[MAX_FINGERS];           /* position array */
+       int slots[MAX_FINGERS];                         /* slot assignments */
 };
 
-/* logical dimensions */
-#define DIM_PRESSURE   256             /* maximum finger pressure */
-#define DIM_WIDTH      16              /* maximum finger width */
-#define DIM_X          1280            /* maximum trackpad x value */
-#define DIM_Y          800             /* maximum trackpad y value */
-
 /* logical signal quality */
 #define SN_PRESSURE    45              /* pressure signal-to-noise ratio */
-#define SN_WIDTH       100             /* width signal-to-noise ratio */
+#define SN_WIDTH       25              /* width signal-to-noise ratio */
 #define SN_COORD       250             /* coordinate signal-to-noise ratio */
-
-/* pressure thresholds */
-#define PRESSURE_LOW   (2 * DIM_PRESSURE / SN_PRESSURE)
-#define PRESSURE_HIGH  (3 * PRESSURE_LOW)
+#define SN_ORIENT      10              /* orientation signal-to-noise ratio */
 
 /* device constants */
 static const struct bcm5974_config bcm5974_config_table[] = {
@@ -261,10 +256,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                0,
                0x84, sizeof(struct bt_data),
                0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
-               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 },
-               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-               { DIM_X, DIM_X / SN_COORD, -4824, 5342 },
-               { DIM_Y, DIM_Y / SN_COORD, -172, 5820 }
+               { SN_PRESSURE, 0, 256 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4824, 5342 },
+               { SN_COORD, -172, 5820 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
        {
                USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI,
@@ -273,10 +269,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                0,
                0x84, sizeof(struct bt_data),
                0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
-               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 },
-               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-               { DIM_X, DIM_X / SN_COORD, -4824, 4824 },
-               { DIM_Y, DIM_Y / SN_COORD, -172, 4290 }
+               { SN_PRESSURE, 0, 256 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4824, 4824 },
+               { SN_COORD, -172, 4290 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
        {
                USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI,
@@ -285,10 +282,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
                0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-               { DIM_X, DIM_X / SN_COORD, -4460, 5166 },
-               { DIM_Y, DIM_Y / SN_COORD, -75, 6700 }
+               { SN_PRESSURE, 0, 300 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4460, 5166 },
+               { SN_COORD, -75, 6700 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
        {
                USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI,
@@ -297,10 +295,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
                0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-               { DIM_X, DIM_X / SN_COORD, -4620, 5140 },
-               { DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+               { SN_PRESSURE, 0, 300 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4620, 5140 },
+               { SN_COORD, -150, 6600 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
        {
                USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI,
@@ -309,10 +308,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
                0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-               { DIM_X, DIM_X / SN_COORD, -4616, 5112 },
-               { DIM_Y, DIM_Y / SN_COORD, -142, 5234 }
+               { SN_PRESSURE, 0, 300 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4616, 5112 },
+               { SN_COORD, -142, 5234 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
        {
                USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI,
@@ -321,10 +321,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
                0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-               { DIM_X, DIM_X / SN_COORD, -4415, 5050 },
-               { DIM_Y, DIM_Y / SN_COORD, -55, 6680 }
+               { SN_PRESSURE, 0, 300 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4415, 5050 },
+               { SN_COORD, -55, 6680 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
        {
                USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI,
@@ -333,10 +334,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
                0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-               { DIM_X, DIM_X / SN_COORD, -4620, 5140 },
-               { DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+               { SN_PRESSURE, 0, 300 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4620, 5140 },
+               { SN_COORD, -150, 6600 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
        {
                USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI,
@@ -345,10 +347,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
                0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-               { DIM_X, DIM_X / SN_COORD, -4750, 5280 },
-               { DIM_Y, DIM_Y / SN_COORD, -150, 6730 }
+               { SN_PRESSURE, 0, 300 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4750, 5280 },
+               { SN_COORD, -150, 6730 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
        {
                USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI,
@@ -357,10 +360,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
                0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-               { DIM_X, DIM_X / SN_COORD, -4620, 5140 },
-               { DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+               { SN_PRESSURE, 0, 300 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4620, 5140 },
+               { SN_COORD, -150, 6600 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
        {
                USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI,
@@ -369,10 +373,11 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
                0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
-               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
-               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
-               { DIM_X, DIM_X / SN_COORD, -4750, 5280 },
-               { DIM_Y, DIM_Y / SN_COORD, -150, 6730 }
+               { SN_PRESSURE, 0, 300 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4750, 5280 },
+               { SN_COORD, -150, 6730 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
        {}
 };
@@ -396,18 +401,11 @@ static inline int raw2int(__le16 x)
        return (signed short)le16_to_cpu(x);
 }
 
-/* scale device data to logical dimensions (asserts devmin < devmax) */
-static inline int int2scale(const struct bcm5974_param *p, int x)
-{
-       return x * p->dim / (p->devmax - p->devmin);
-}
-
-/* all logical value ranges are [0,dim). */
-static inline int int2bound(const struct bcm5974_param *p, int x)
+static void set_abs(struct input_dev *input, unsigned int code,
+                   const struct bcm5974_param *p)
 {
-       int s = int2scale(p, x);
-
-       return clamp_val(s, 0, p->dim - 1);
+       int fuzz = p->snratio ? (p->max - p->min) / p->snratio : 0;
+       input_set_abs_params(input, code, p->min, p->max, fuzz, 0);
 }
 
 /* setup which logical events to report */
@@ -416,48 +414,30 @@ static void setup_events_to_report(struct input_dev *input_dev,
 {
        __set_bit(EV_ABS, input_dev->evbit);
 
-       input_set_abs_params(input_dev, ABS_PRESSURE,
-                               0, cfg->p.dim, cfg->p.fuzz, 0);
-       input_set_abs_params(input_dev, ABS_TOOL_WIDTH,
-                               0, cfg->w.dim, cfg->w.fuzz, 0);
-       input_set_abs_params(input_dev, ABS_X,
-                               0, cfg->x.dim, cfg->x.fuzz, 0);
-       input_set_abs_params(input_dev, ABS_Y,
-                               0, cfg->y.dim, cfg->y.fuzz, 0);
+       /* for synaptics only */
+       input_set_abs_params(input_dev, ABS_PRESSURE, 0, 256, 5, 0);
+       input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 16, 0, 0);
 
        /* finger touch area */
-       input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
-                            cfg->w.devmin, cfg->w.devmax, 0, 0);
-       input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
-                            cfg->w.devmin, cfg->w.devmax, 0, 0);
+       set_abs(input_dev, ABS_MT_TOUCH_MAJOR, &cfg->w);
+       set_abs(input_dev, ABS_MT_TOUCH_MINOR, &cfg->w);
        /* finger approach area */
-       input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR,
-                            cfg->w.devmin, cfg->w.devmax, 0, 0);
-       input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR,
-                            cfg->w.devmin, cfg->w.devmax, 0, 0);
+       set_abs(input_dev, ABS_MT_WIDTH_MAJOR, &cfg->w);
+       set_abs(input_dev, ABS_MT_WIDTH_MINOR, &cfg->w);
        /* finger orientation */
-       input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
-                            -MAX_FINGER_ORIENTATION,
-                            MAX_FINGER_ORIENTATION, 0, 0);
+       set_abs(input_dev, ABS_MT_ORIENTATION, &cfg->o);
        /* finger position */
-       input_set_abs_params(input_dev, ABS_MT_POSITION_X,
-                            cfg->x.devmin, cfg->x.devmax, 0, 0);
-       input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
-                            cfg->y.devmin, cfg->y.devmax, 0, 0);
+       set_abs(input_dev, ABS_MT_POSITION_X, &cfg->x);
+       set_abs(input_dev, ABS_MT_POSITION_Y, &cfg->y);
 
        __set_bit(EV_KEY, input_dev->evbit);
-       __set_bit(BTN_TOUCH, input_dev->keybit);
-       __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
-       __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
-       __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
-       __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
        __set_bit(BTN_LEFT, input_dev->keybit);
 
-       __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
        if (cfg->caps & HAS_INTEGRATED_BUTTON)
                __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
 
-       input_set_events_per_packet(input_dev, 60);
+       input_mt_init_slots(input_dev, MAX_FINGERS,
+               INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK);
 }
 
 /* report button data as logical button state */
@@ -477,24 +457,44 @@ static int report_bt_state(struct bcm5974 *dev, int size)
        return 0;
 }
 
-static void report_finger_data(struct input_dev *input,
-                              const struct bcm5974_config *cfg,
+static void report_finger_data(struct input_dev *input, int slot,
+                              const struct input_mt_pos *pos,
                               const struct tp_finger *f)
 {
+       input_mt_slot(input, slot);
+       input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+
        input_report_abs(input, ABS_MT_TOUCH_MAJOR,
-                        raw2int(f->force_major) << 1);
+                        raw2int(f->touch_major) << 1);
        input_report_abs(input, ABS_MT_TOUCH_MINOR,
-                        raw2int(f->force_minor) << 1);
+                        raw2int(f->touch_minor) << 1);
        input_report_abs(input, ABS_MT_WIDTH_MAJOR,
-                        raw2int(f->size_major) << 1);
+                        raw2int(f->tool_major) << 1);
        input_report_abs(input, ABS_MT_WIDTH_MINOR,
-                        raw2int(f->size_minor) << 1);
+                        raw2int(f->tool_minor) << 1);
        input_report_abs(input, ABS_MT_ORIENTATION,
                         MAX_FINGER_ORIENTATION - raw2int(f->orientation));
-       input_report_abs(input, ABS_MT_POSITION_X, raw2int(f->abs_x));
-       input_report_abs(input, ABS_MT_POSITION_Y,
-                        cfg->y.devmin + cfg->y.devmax - raw2int(f->abs_y));
-       input_mt_sync(input);
+       input_report_abs(input, ABS_MT_POSITION_X, pos->x);
+       input_report_abs(input, ABS_MT_POSITION_Y, pos->y);
+}
+
+static void report_synaptics_data(struct input_dev *input,
+                                 const struct bcm5974_config *cfg,
+                                 const struct tp_finger *f, int raw_n)
+{
+       int abs_p = 0, abs_w = 0;
+
+       if (raw_n) {
+               int p = raw2int(f->touch_major);
+               int w = raw2int(f->tool_major);
+               if (p > 0 && raw2int(f->origin)) {
+                       abs_p = clamp_val(256 * p / cfg->p.max, 0, 255);
+                       abs_w = clamp_val(16 * w / cfg->w.max, 0, 15);
+               }
+       }
+
+       input_report_abs(input, ABS_PRESSURE, abs_p);
+       input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
 }
 
 /* report trackpad data as logical trackpad state */
@@ -503,9 +503,7 @@ static int report_tp_state(struct bcm5974 *dev, int size)
        const struct bcm5974_config *c = &dev->cfg;
        const struct tp_finger *f;
        struct input_dev *input = dev->input;
-       int raw_p, raw_w, raw_x, raw_y, raw_n, i;
-       int ptest, origin, ibt = 0, nmin = 0, nmax = 0;
-       int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
+       int raw_n, i, n = 0;
 
        if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0)
                return -EIO;
@@ -514,76 +512,29 @@ static int report_tp_state(struct bcm5974 *dev, int size)
        f = (const struct tp_finger *)(dev->tp_data + c->tp_offset);
        raw_n = (size - c->tp_offset) / SIZEOF_FINGER;
 
-       /* always track the first finger; when detached, start over */
-       if (raw_n) {
-
-               /* report raw trackpad data */
-               for (i = 0; i < raw_n; i++)
-                       report_finger_data(input, c, &f[i]);
-
-               raw_p = raw2int(f->force_major);
-               raw_w = raw2int(f->size_major);
-               raw_x = raw2int(f->abs_x);
-               raw_y = raw2int(f->abs_y);
-
-               dprintk(9,
-                       "bcm5974: "
-                       "raw: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n",
-                       raw_p, raw_w, raw_x, raw_y, raw_n);
-
-               ptest = int2bound(&c->p, raw_p);
-               origin = raw2int(f->origin);
-
-               /* while tracking finger still valid, count all fingers */
-               if (ptest > PRESSURE_LOW && origin) {
-                       abs_p = ptest;
-                       abs_w = int2bound(&c->w, raw_w);
-                       abs_x = int2bound(&c->x, raw_x - c->x.devmin);
-                       abs_y = int2bound(&c->y, c->y.devmax - raw_y);
-                       while (raw_n--) {
-                               ptest = int2bound(&c->p,
-                                                 raw2int(f->force_major));
-                               if (ptest > PRESSURE_LOW)
-                                       nmax++;
-                               if (ptest > PRESSURE_HIGH)
-                                       nmin++;
-                               f++;
-                       }
-               }
+       for (i = 0; i < raw_n; i++) {
+               if (raw2int(f[i].touch_major) == 0)
+                       continue;
+               dev->pos[n].x = raw2int(f[i].abs_x);
+               dev->pos[n].y = c->y.min + c->y.max - raw2int(f[i].abs_y);
+               dev->index[n++] = &f[i];
        }
 
-       /* set the integrated button if applicable */
-       if (c->tp_type == TYPE2)
-               ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
-
-       if (dev->fingers < nmin)
-               dev->fingers = nmin;
-       if (dev->fingers > nmax)
-               dev->fingers = nmax;
-
-       input_report_key(input, BTN_TOUCH, dev->fingers > 0);
-       input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1);
-       input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2);
-       input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers == 3);
-       input_report_key(input, BTN_TOOL_QUADTAP, dev->fingers > 3);
-
-       input_report_abs(input, ABS_PRESSURE, abs_p);
-       input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
+       input_mt_assign_slots(input, dev->slots, dev->pos, n);
 
-       if (abs_p) {
-               input_report_abs(input, ABS_X, abs_x);
-               input_report_abs(input, ABS_Y, abs_y);
+       for (i = 0; i < n; i++)
+               report_finger_data(input, dev->slots[i],
+                                  &dev->pos[i], dev->index[i]);
 
-               dprintk(8,
-                       "bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d "
-                       "nmin: %d nmax: %d n: %d ibt: %d\n", abs_p, abs_w,
-                       abs_x, abs_y, nmin, nmax, dev->fingers, ibt);
+       input_mt_sync_frame(input);
 
-       }
+       report_synaptics_data(input, c, f, raw_n);
 
        /* type 2 reports button events via ibt only */
-       if (c->tp_type == TYPE2)
+       if (c->tp_type == TYPE2) {
+               int ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
                input_report_key(input, BTN_LEFT, ibt);
+       }
 
        input_sync(input);
 
@@ -742,9 +693,11 @@ static int bcm5974_start_traffic(struct bcm5974 *dev)
                goto err_out;
        }
 
-       error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
-       if (error)
-               goto err_reset_mode;
+       if (dev->bt_urb) {
+               error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
+               if (error)
+                       goto err_reset_mode;
+       }
 
        error = usb_submit_urb(dev->tp_urb, GFP_KERNEL);
        if (error)
@@ -868,19 +821,23 @@ static int bcm5974_probe(struct usb_interface *iface,
        mutex_init(&dev->pm_mutex);
 
        /* setup urbs */
-       dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!dev->bt_urb)
-               goto err_free_devs;
+       if (cfg->tp_type == TYPE1) {
+               dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!dev->bt_urb)
+                       goto err_free_devs;
+       }
 
        dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!dev->tp_urb)
                goto err_free_bt_urb;
 
-       dev->bt_data = usb_alloc_coherent(dev->udev,
+       if (dev->bt_urb) {
+               dev->bt_data = usb_alloc_coherent(dev->udev,
                                          dev->cfg.bt_datalen, GFP_KERNEL,
                                          &dev->bt_urb->transfer_dma);
-       if (!dev->bt_data)
-               goto err_free_urb;
+               if (!dev->bt_data)
+                       goto err_free_urb;
+       }
 
        dev->tp_data = usb_alloc_coherent(dev->udev,
                                          dev->cfg.tp_datalen, GFP_KERNEL,
@@ -888,10 +845,11 @@ static int bcm5974_probe(struct usb_interface *iface,
        if (!dev->tp_data)
                goto err_free_bt_buffer;
 
-       usb_fill_int_urb(dev->bt_urb, udev,
-                        usb_rcvintpipe(udev, cfg->bt_ep),
-                        dev->bt_data, dev->cfg.bt_datalen,
-                        bcm5974_irq_button, dev, 1);
+       if (dev->bt_urb)
+               usb_fill_int_urb(dev->bt_urb, udev,
+                                usb_rcvintpipe(udev, cfg->bt_ep),
+                                dev->bt_data, dev->cfg.bt_datalen,
+                                bcm5974_irq_button, dev, 1);
 
        usb_fill_int_urb(dev->tp_urb, udev,
                         usb_rcvintpipe(udev, cfg->tp_ep),
@@ -929,8 +887,9 @@ err_free_buffer:
        usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
                dev->tp_data, dev->tp_urb->transfer_dma);
 err_free_bt_buffer:
-       usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
-               dev->bt_data, dev->bt_urb->transfer_dma);
+       if (dev->bt_urb)
+               usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
+                                 dev->bt_data, dev->bt_urb->transfer_dma);
 err_free_urb:
        usb_free_urb(dev->tp_urb);
 err_free_bt_urb:
@@ -951,8 +910,9 @@ static void bcm5974_disconnect(struct usb_interface *iface)
        input_unregister_device(dev->input);
        usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
                          dev->tp_data, dev->tp_urb->transfer_dma);
-       usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
-                         dev->bt_data, dev->bt_urb->transfer_dma);
+       if (dev->bt_urb)
+               usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
+                                 dev->bt_data, dev->bt_urb->transfer_dma);
        usb_free_urb(dev->tp_urb);
        usb_free_urb(dev->bt_urb);
        kfree(dev);
index 479011004a111dcf41cc344356da29e3deb74902..1e8e42fb03a4258d0b04f34d5872440ee293fe5b 100644 (file)
@@ -1004,7 +1004,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
                        input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
                                             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_Y, y_min, y_max, 0, 0);
                break;
@@ -1035,7 +1035,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
                input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
                                     ETP_WMAX_V2, 0, 0);
                /* 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_Y, y_min, y_max, 0, 0);
                input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
index 3f5649f190824408a25c495bdfd4da88b8febe9a..b47155d8bc8c3ef0effc46b565f18f9371dffab3 100644 (file)
@@ -960,7 +960,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_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_Y, 0, abs_y, 0, 0);
        }
index 14eaecea2b70660f7377c0a3196809e28c406d4a..37033ade79d3c70881517f128d7a3d0141919099 100644 (file)
@@ -1232,7 +1232,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);
 
        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,
                                        ABS_MT_POSITION_Y);
                /* Image sensors can report per-contact pressure */
@@ -1244,7 +1244,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
        } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
                /* Non-image sensors with AGM use semi-mt */
                __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,
                                        ABS_MT_POSITION_Y);
        }
index 532d067a9e07a0745188eb3dab8e4025ef7b664f..2a81ce375f756d0989bd3a6592efc6641137e9a5 100644 (file)
@@ -1530,7 +1530,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
                        __set_bit(BTN_TOOL_TRIPLETAP, 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,
                                             0, 255, 0, 0);
@@ -1575,7 +1575,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 
        case TABLETPC2FG:
                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,
                                        0, MT_TOOL_MAX, 0, 0);
                        input_set_abs_params(input_dev, ABS_MT_POSITION_X,
@@ -1631,7 +1631,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 
                        __set_bit(BTN_TOOL_FINGER, 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) {
                                __set_bit(BTN_TOOL_TRIPLETAP,
index 4623cc69fc603ab6825a9793dd3e9e4e887b2657..e92615d0b1b0330b334b1a54a603354fdc3a8960 100644 (file)
@@ -1152,7 +1152,7 @@ static int __devinit mxt_probe(struct i2c_client *client,
 
        /* For multi touch */
        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)
                goto err_free_object;
        input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
index f030d9ec795d0ae062a76260ff2943a28101e384..8e60437ac85b46569e57ae78f2bea455fd1b9ab5 100644 (file)
@@ -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,
                             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,
                                     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
index 9afc777a40a7077a5bbd667944f1c1ee3bac38d7..7b786e757ba26c075b9617170f2da9269f51ccfd 100644 (file)
@@ -778,7 +778,7 @@ static int __devinit edt_ft5x06_ts_probe(struct i2c_client *client,
                             0, tsdata->num_x * 64 - 1, 0, 0);
        input_set_abs_params(input, ABS_MT_POSITION_Y,
                             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) {
                dev_err(&client->dev, "Unable to init MT slots.\n");
                goto err_free_mem;
index 70524dd34f4277f3934f48c8b07e0d3cc84d6b21..c1e3460f1195aed3953c0e09542c9718d8664421 100644 (file)
@@ -204,7 +204,7 @@ static int __devinit egalax_ts_probe(struct i2c_client *client,
                             ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0);
        input_set_abs_params(input_dev,
                             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);
 
index c0044175a921b1703842facefd0d7f9fd36cde3e..4ac69760ec08702577100b65a98d5288a24daf46 100644 (file)
@@ -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);
 
        /* 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_Y, 0, ymax, 0, 0);
 
index 49c44bbf548d1a308b53bad306450aab66831f28..560cf09d1c5a893215f9aca033a6ea4327dfed7c 100644 (file)
@@ -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);
 
        /* 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,
                             0, MMS114_MAX_AREA, 0, 0);
        input_set_abs_params(input_dev, ABS_MT_POSITION_X,
index 4ccde45b9da2bfac620f81c62aa9c6b95d5f873c..b49f0b836925a63c5142990cb87975900e7f5323 100644 (file)
@@ -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);
 
        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,
                                     ABS_MT_POSITION_X, 0, max_x, 0, 0);
                input_set_abs_params(pm->dev,
index 8f9ad2f893b825a0c2d3afc5a9777ec098003308..9a83be6b6584f8f3af131767197916c65c8c1000 100644 (file)
@@ -471,7 +471,7 @@ static int w8001_setup(struct w8001 *w8001)
                case 5:
                        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,
                                                0, touch.x, 0, 0);
                        input_set_abs_params(dev, ABS_MT_POSITION_Y,
index 42970de1b40c50deb1584d8f7aa459ccd4173a08..7e1f37db7582260231fa8bb6edf435335e4e128b 100644 (file)
@@ -414,7 +414,7 @@ struct hid_field {
        __u16 dpad;                     /* dpad input code */
 };
 
-#define HID_MAX_FIELDS 128
+#define HID_MAX_FIELDS 256
 
 struct hid_report {
        struct list_head list;
@@ -626,6 +626,7 @@ struct hid_usage_id {
  * @report_fixup: called before report descriptor parsing (NULL means nop)
  * @input_mapping: invoked on input registering before 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
  * @suspend: invoked on suspend (NULL means nop)
  * @resume: invoked on resume if device was not reset (NULL means nop)
@@ -670,6 +671,8 @@ struct hid_driver {
        int (*input_mapped)(struct hid_device *hdev,
                        struct hid_input *hidinput, struct hid_field *field,
                        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,
                        struct hid_field *field,
                        struct hid_usage *usage);
index 725dcd0f63a4bf262f05555c528a20c68d8b1a75..ba4874302939a8a645c99ac8c53f35772f57cd37 100644 (file)
@@ -1168,6 +1168,18 @@ struct ff_effect {
 #include <linux/timer.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
  * @name: name of the device
@@ -1203,11 +1215,7 @@ struct ff_effect {
  *     software autorepeat
  * @timer: timer for software autorepeat
  * @rep: current values for autorepeat parameters (delay, rate)
- * @mt: pointer to array of struct input_mt_slot holding current values
- *     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
+ * @mt: pointer to multitouch state
  * @absinfo: array of &struct input_absinfo elements holding information
  *     about absolute axes (current value, min, max, flat, fuzz,
  *     resolution)
@@ -1244,7 +1252,6 @@ struct ff_effect {
  *     last user closes the device
  * @going_away: marks devices that are in a middle of unregistering and
  *     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
  * @h_list: list of input handles associated with the device. When
  *     accessing the list dev->mutex must be held
@@ -1287,10 +1294,7 @@ struct input_dev {
 
        int rep[REP_CNT];
 
-       struct input_mt_slot *mt;
-       int mtsize;
-       int slot;
-       int trkid;
+       struct input_mt *mt;
 
        struct input_absinfo *absinfo;
 
@@ -1312,12 +1316,14 @@ struct input_dev {
        unsigned int users;
        bool going_away;
 
-       bool sync;
-
        struct device dev;
 
        struct list_head        h_list;
        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)
 
@@ -1378,6 +1384,9 @@ struct input_handle;
  * @event: event handler. This method is being called by input core with
  *     interrupts disabled and dev->event_lock spinlock held and so
  *     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
  *     "filters".
  * @match: called after comparing device's id with handler's id_table
@@ -1414,6 +1423,8 @@ struct input_handler {
        void *private;
 
        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 (*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);
index f86737586e190364a09c882afbab7890e66bde04..cc5cca774bab14590e544f682c96a4ab72cd89c4 100644 (file)
 
 #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
  * @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 {
        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,
@@ -35,12 +64,18 @@ static inline int input_mt_get_value(const struct input_mt_slot *slot,
        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);
 
-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)
@@ -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_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