Input: wacom - add support for EMR on Cintiq 24HD touch
[firefly-linux-kernel-4.4.55.git] / drivers / input / tablet / wacom_wac.c
index cecd35c8f0b3ce46cb82bd51514f7b468ab282cd..532d067a9e07a0745188eb3dab8e4025ef7b664f 100644 (file)
@@ -61,7 +61,8 @@ static int wacom_penpartner_irq(struct wacom_wac *wacom)
                break;
 
        default:
-               printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
+               dev_dbg(input->dev.parent,
+                       "%s: received unknown report #%d\n", __func__, data[0]);
                return 0;
         }
 
@@ -76,7 +77,8 @@ static int wacom_pl_irq(struct wacom_wac *wacom)
        int prox, pressure;
 
        if (data[0] != WACOM_REPORT_PENABLED) {
-               dbg("wacom_pl_irq: received unknown report #%d", data[0]);
+               dev_dbg(input->dev.parent,
+                       "%s: received unknown report #%d\n", __func__, data[0]);
                return 0;
        }
 
@@ -146,7 +148,8 @@ static int wacom_ptu_irq(struct wacom_wac *wacom)
        struct input_dev *input = wacom->input;
 
        if (data[0] != WACOM_REPORT_PENABLED) {
-               printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
+               dev_dbg(input->dev.parent,
+                       "%s: received unknown report #%d\n", __func__, data[0]);
                return 0;
        }
 
@@ -175,7 +178,8 @@ static int wacom_dtu_irq(struct wacom_wac *wacom)
        struct input_dev *input = wacom->input;
        int prox = data[1] & 0x20, pressure;
 
-       dbg("wacom_dtu_irq: received report #%d", data[0]);
+       dev_dbg(input->dev.parent,
+               "%s: received report #%d", __func__, data[0]);
 
        if (prox) {
                /* Going into proximity select tool */
@@ -211,7 +215,8 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
        int retval = 0;
 
        if (data[0] != WACOM_REPORT_PENABLED) {
-               dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
+               dev_dbg(input->dev.parent,
+                       "%s: received unknown report #%d\n", __func__, data[0]);
                goto exit;
        }
 
@@ -243,7 +248,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
                input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
                input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
                if (wacom->tool[0] != BTN_TOOL_MOUSE) {
-                       input_report_abs(input, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8));
+                       input_report_abs(input, ABS_PRESSURE, data[6] | ((data[7] & 0x03) << 8));
                        input_report_key(input, BTN_TOUCH, data[1] & 0x01);
                        input_report_key(input, BTN_STYLUS, data[1] & 0x02);
                        input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
@@ -321,6 +326,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
 
        /* Enter report */
        if ((data[1] & 0xfc) == 0xc0) {
+               if (features->type >= INTUOS5S && features->type <= INTUOS5L)
+                       wacom->shared->stylus_in_proximity = true;
+
                /* serial number of the tool */
                wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
                        (data[4] << 20) + (data[5] << 12) +
@@ -406,6 +414,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
 
        /* Exit report */
        if ((data[1] & 0xfe) == 0x80) {
+               if (features->type >= INTUOS5S && features->type <= INTUOS5L)
+                       wacom->shared->stylus_in_proximity = false;
+
                /*
                 * Reset all states otherwise we lose the initial states
                 * when in-prox next time
@@ -452,7 +463,8 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
        if ((data[1] & 0xb8) == 0xa0) {
                t = (data[6] << 2) | ((data[7] >> 6) & 3);
                if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
-                   features->type == WACOM_21UX2 || features->type == WACOM_24HD) {
+                    (features->type >= INTUOS5S && features->type <= INTUOS5L) ||
+                   (features->type >= WACOM_21UX2 && features->type <= WACOM_24HD)) {
                        t = (t << 1) | (data[1] & 1);
                }
                input_report_abs(input, ABS_PRESSURE, t);
@@ -482,9 +494,13 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
        unsigned int t;
        int idx = 0, result;
 
-       if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_INTUOSREAD
-               && data[0] != WACOM_REPORT_INTUOSWRITE && data[0] != WACOM_REPORT_INTUOSPAD) {
-               dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
+       if (data[0] != WACOM_REPORT_PENABLED &&
+           data[0] != WACOM_REPORT_INTUOSREAD &&
+           data[0] != WACOM_REPORT_INTUOSWRITE &&
+           data[0] != WACOM_REPORT_INTUOSPAD &&
+           data[0] != WACOM_REPORT_INTUOS5PAD) {
+               dev_dbg(input->dev.parent,
+                       "%s: received unknown report #%d\n", __func__, data[0]);
                 return 0;
        }
 
@@ -493,7 +509,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                idx = data[1] & 0x01;
 
        /* pad packets. Works as a second tool and is always in prox */
-       if (data[0] == WACOM_REPORT_INTUOSPAD) {
+       if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) {
                if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
                        input_report_key(input, BTN_0, (data[2] & 0x01));
                        input_report_key(input, BTN_1, (data[3] & 0x01));
@@ -569,8 +585,36 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                                input_report_key(input, wacom->tool[1], 0);
                                input_report_abs(input, ABS_MISC, 0);
                        }
+               } else if (features->type >= INTUOS5S && features->type <= INTUOS5L) {
+                       int i;
+
+                       /* Touch ring mode switch has no capacitive sensor */
+                       input_report_key(input, BTN_0, (data[3] & 0x01));
+
+                       /*
+                        * ExpressKeys on Intuos5 have a capacitive sensor in
+                        * addition to the mechanical switch. Switch data is
+                        * stored in data[4], capacitive data in data[5].
+                        */
+                       for (i = 0; i < 8; i++)
+                               input_report_key(input, BTN_1 + i, data[4] & (1 << i));
+
+                       if (data[2] & 0x80) {
+                               input_report_abs(input, ABS_WHEEL, (data[2] & 0x7f));
+                       } else {
+                               /* Out of proximity, clear wheel value. */
+                               input_report_abs(input, ABS_WHEEL, 0);
+                       }
+
+                       if (data[2] | (data[3] & 0x01) | data[4]) {
+                               input_report_key(input, wacom->tool[1], 1);
+                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+                       } else {
+                               input_report_key(input, wacom->tool[1], 0);
+                               input_report_abs(input, ABS_MISC, 0);
+                       }
                } else {
-                       if (features->type == WACOM_21UX2) {
+                       if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
                                input_report_key(input, BTN_0, (data[5] & 0x01));
                                input_report_key(input, BTN_1, (data[6] & 0x01));
                                input_report_key(input, BTN_2, (data[6] & 0x02));
@@ -589,6 +633,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                                input_report_key(input, BTN_Z, (data[8] & 0x20));
                                input_report_key(input, BTN_BASE, (data[8] & 0x40));
                                input_report_key(input, BTN_BASE2, (data[8] & 0x80));
+
+                               if (features->type == WACOM_22HD) {
+                                       input_report_key(input, KEY_PROG1, data[9] & 0x01);
+                                       input_report_key(input, KEY_PROG2, data[9] & 0x02);
+                                       input_report_key(input, KEY_PROG3, data[9] & 0x04);
+                               }
                        } else {
                                input_report_key(input, BTN_0, (data[5] & 0x01));
                                input_report_key(input, BTN_1, (data[5] & 0x02));
@@ -632,7 +682,9 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
            (features->type == INTUOS3 ||
             features->type == INTUOS3S ||
             features->type == INTUOS4 ||
-            features->type == INTUOS4S)) {
+            features->type == INTUOS4S ||
+            features->type == INTUOS5 ||
+            features->type == INTUOS5S)) {
 
                return 0;
        }
@@ -685,7 +737,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
 
                } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
                        /* I4 mouse */
-                       if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
+                       if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
+                           (features->type >= INTUOS5S && features->type <= INTUOS5L)) {
                                input_report_key(input, BTN_LEFT,   data[6] & 0x01);
                                input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
                                input_report_key(input, BTN_RIGHT,  data[6] & 0x04);
@@ -712,7 +765,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                                }
                        }
                } else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
-                               features->type == INTUOS4L) &&
+                               features->type == INTUOS4L || features->type == INTUOS5L) &&
                           wacom->tool[idx] == BTN_TOOL_LENS) {
                        /* Lens cursor packets */
                        input_report_key(input, BTN_LEFT,   data[8] & 0x01);
@@ -729,6 +782,72 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
        return 1;
 }
 
+static int find_slot_from_contactid(struct wacom_wac *wacom, int contactid)
+{
+       int touch_max = wacom->features.touch_max;
+       int i;
+
+       if (!wacom->slots)
+               return -1;
+
+       for (i = 0; i < touch_max; ++i) {
+               if (wacom->slots[i] == contactid)
+                       return i;
+       }
+       for (i = 0; i < touch_max; ++i) {
+               if (wacom->slots[i] == -1)
+                       return i;
+       }
+       return -1;
+}
+
+static int wacom_mt_touch(struct wacom_wac *wacom)
+{
+       struct input_dev *input = wacom->input;
+       char *data = wacom->data;
+       int i;
+       int current_num_contacts = data[2];
+       int contacts_to_send = 0;
+
+       /*
+        * First packet resets the counter since only the first
+        * packet in series will have non-zero current_num_contacts.
+        */
+       if (current_num_contacts)
+               wacom->num_contacts_left = current_num_contacts;
+
+       /* There are at most 5 contacts per packet */
+       contacts_to_send = min(5, wacom->num_contacts_left);
+
+       for (i = 0; i < contacts_to_send; i++) {
+               int offset = (WACOM_BYTES_PER_MT_PACKET * i) + 3;
+               bool touch = data[offset] & 0x1;
+               int id = le16_to_cpup((__le16 *)&data[offset + 1]);
+               int slot = find_slot_from_contactid(wacom, id);
+
+               if (slot < 0)
+                       continue;
+
+               input_mt_slot(input, slot);
+               input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+               if (touch) {
+                       int x = le16_to_cpup((__le16 *)&data[offset + 7]);
+                       int y = le16_to_cpup((__le16 *)&data[offset + 9]);
+                       input_report_abs(input, ABS_MT_POSITION_X, x);
+                       input_report_abs(input, ABS_MT_POSITION_Y, y);
+               }
+               wacom->slots[slot] = touch ? id : -1;
+       }
+
+       input_mt_report_pointer_emulation(input, true);
+
+       wacom->num_contacts_left -= contacts_to_send;
+       if (wacom->num_contacts_left < 0)
+               wacom->num_contacts_left = 0;
+
+       return 1;
+}
+
 static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
 {
        struct input_dev *input = wacom->input;
@@ -767,12 +886,15 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
        bool prox;
        int x = 0, y = 0;
 
+       if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
+               return 0;
+
        if (!wacom->shared->stylus_in_proximity) {
                if (len == WACOM_PKGLEN_TPC1FG) {
                        prox = data[0] & 0x01;
                        x = get_unaligned_le16(&data[1]);
                        y = get_unaligned_le16(&data[3]);
-               } else { /* with capacity */
+               } else {
                        prox = data[1] & 0x01;
                        x = le16_to_cpup((__le16 *)&data[2]);
                        y = le16_to_cpup((__le16 *)&data[4]);
@@ -830,22 +952,27 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
 {
        char *data = wacom->data;
 
-       dbg("wacom_tpc_irq: received report #%d", data[0]);
+       dev_dbg(wacom->input->dev.parent,
+               "%s: received report #%d\n", __func__, data[0]);
 
        switch (len) {
        case WACOM_PKGLEN_TPC1FG:
-                return wacom_tpc_single_touch(wacom, len);
+               return wacom_tpc_single_touch(wacom, len);
 
        case WACOM_PKGLEN_TPC2FG:
-               return wacom_tpc_mt_touch(wacom);
+               return wacom_tpc_mt_touch(wacom);
 
        default:
                switch (data[0]) {
                case WACOM_REPORT_TPC1FG:
                case WACOM_REPORT_TPCHID:
                case WACOM_REPORT_TPCST:
+               case WACOM_REPORT_TPC1FGE:
                        return wacom_tpc_single_touch(wacom, len);
 
+               case WACOM_REPORT_TPCMT:
+                       return wacom_mt_touch(wacom);
+
                case WACOM_REPORT_PENABLED:
                        return wacom_tpc_pen(wacom);
                }
@@ -1110,12 +1237,24 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
        case CINTIQ:
        case WACOM_BEE:
        case WACOM_21UX2:
+       case WACOM_22HD:
        case WACOM_24HD:
                sync = wacom_intuos_irq(wacom_wac);
                break;
 
+       case INTUOS5S:
+       case INTUOS5:
+       case INTUOS5L:
+               if (len == WACOM_PKGLEN_BBTOUCH3)
+                       sync = wacom_bpt3_touch(wacom_wac);
+               else
+                       sync = wacom_intuos_irq(wacom_wac);
+               break;
+
        case TABLETPC:
+       case TABLETPCE:
        case TABLETPC2FG:
+       case MTSCREEN:
                sync = wacom_tpc_irq(wacom_wac, len);
                break;
 
@@ -1187,8 +1326,8 @@ void wacom_setup_device_quirks(struct wacom_features *features)
        }
 
        /* these device have multiple inputs */
-       if (features->type == TABLETPC || features->type == TABLETPC2FG ||
-           features->type == BAMBOO_PT || features->type == WIRELESS)
+       if (features->type >= WIRELESS ||
+           (features->type >= INTUOS5S && features->type <= INTUOS5L))
                features->quirks |= WACOM_QUIRK_MULTI_INPUT;
 
        /* quirk for bamboo touch with 2 low res touches */
@@ -1219,8 +1358,8 @@ static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
        return (logical_max * 100) / physical_max;
 }
 
-void wacom_setup_input_capabilities(struct input_dev *input_dev,
-                                   struct wacom_wac *wacom_wac)
+int wacom_setup_input_capabilities(struct input_dev *input_dev,
+                                  struct wacom_wac *wacom_wac)
 {
        struct wacom_features *features = &wacom_wac->features;
        int i;
@@ -1300,6 +1439,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                wacom_setup_cintiq(wacom_wac);
                break;
 
+       case WACOM_22HD:
+               __set_bit(KEY_PROG1, input_dev->keybit);
+               __set_bit(KEY_PROG2, input_dev->keybit);
+               __set_bit(KEY_PROG3, input_dev->keybit);
+               /* fall through */
+
        case WACOM_21UX2:
                __set_bit(BTN_A, input_dev->keybit);
                __set_bit(BTN_B, input_dev->keybit);
@@ -1355,6 +1500,50 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                wacom_setup_intuos(wacom_wac);
                break;
 
+       case INTUOS5:
+       case INTUOS5L:
+               if (features->device_type == BTN_TOOL_PEN) {
+                       __set_bit(BTN_7, input_dev->keybit);
+                       __set_bit(BTN_8, input_dev->keybit);
+               }
+               /* fall through */
+
+       case INTUOS5S:
+               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
+               if (features->device_type == BTN_TOOL_PEN) {
+                       for (i = 0; i < 7; i++)
+                               __set_bit(BTN_0 + i, input_dev->keybit);
+
+                       input_set_abs_params(input_dev, ABS_DISTANCE, 0,
+                                             features->distance_max,
+                                             0, 0);
+
+                       input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+
+                       wacom_setup_intuos(wacom_wac);
+               } else if (features->device_type == BTN_TOOL_FINGER) {
+                       __clear_bit(ABS_MISC, input_dev->absbit);
+
+                       __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);
+
+                       input_mt_init_slots(input_dev, features->touch_max);
+
+                       input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+                                            0, 255, 0, 0);
+
+                       input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+                                            0, features->x_max,
+                                            features->x_fuzz, 0);
+                       input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+                                            0, features->y_max,
+                                            features->y_fuzz, 0);
+               }
+               break;
+
        case INTUOS4:
        case INTUOS4L:
                __set_bit(BTN_7, input_dev->keybit);
@@ -1371,10 +1560,22 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
                break;
 
-       case TABLETPC2FG:
+       case MTSCREEN:
                if (features->device_type == BTN_TOOL_FINGER) {
+                       wacom_wac->slots = kmalloc(features->touch_max *
+                                                       sizeof(int),
+                                                  GFP_KERNEL);
+                       if (!wacom_wac->slots)
+                               return -ENOMEM;
+
+                       for (i = 0; i < features->touch_max; i++)
+                               wacom_wac->slots[i] = -1;
+               }
+               /* fall through */
 
-                       input_mt_init_slots(input_dev, 2);
+       case TABLETPC2FG:
+               if (features->device_type == BTN_TOOL_FINGER) {
+                       input_mt_init_slots(input_dev, features->touch_max);
                        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,
@@ -1385,6 +1586,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                /* fall through */
 
        case TABLETPC:
+       case TABLETPCE:
                __clear_bit(ABS_MISC, input_dev->absbit);
 
                __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
@@ -1429,6 +1631,7 @@ void 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);
 
                        if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
                                __set_bit(BTN_TOOL_TRIPLETAP,
@@ -1436,13 +1639,9 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                                __set_bit(BTN_TOOL_QUADTAP,
                                          input_dev->keybit);
 
-                               input_mt_init_slots(input_dev, 16);
-
                                input_set_abs_params(input_dev,
                                                     ABS_MT_TOUCH_MAJOR,
                                                     0, 255, 0, 0);
-                       } else {
-                               input_mt_init_slots(input_dev, 2);
                        }
 
                        input_set_abs_params(input_dev, ABS_MT_POSITION_X,
@@ -1462,6 +1661,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                }
                break;
        }
+       return 0;
 }
 
 static const struct wacom_features wacom_features_0x00 =
@@ -1629,8 +1829,29 @@ static const struct wacom_features wacom_features_0xBB =
 static const struct wacom_features wacom_features_0xBC =
        { "Wacom Intuos4 WL",     WACOM_PKGLEN_INTUOS,    40840, 25400, 2047,
          63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x26 =
+       { "Wacom Intuos5 touch S", WACOM_PKGLEN_INTUOS,  31496, 19685, 2047,
+         63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         .touch_max = 16 };
+static const struct wacom_features wacom_features_0x27 =
+       { "Wacom Intuos5 touch M", WACOM_PKGLEN_INTUOS,  44704, 27940, 2047,
+         63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         .touch_max = 16 };
+static const struct wacom_features wacom_features_0x28 =
+       { "Wacom Intuos5 touch L", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047,
+         63, INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         .touch_max = 16 };
+static const struct wacom_features wacom_features_0x29 =
+       { "Wacom Intuos5 S", WACOM_PKGLEN_INTUOS,  31496, 19685, 2047,
+         63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x2A =
+       { "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS,  44704, 27940, 2047,
+         63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xF4 =
-       { "Wacom Cintiq 24HD",    WACOM_PKGLEN_INTUOS,   104480, 65600, 2047,
+       { "Wacom Cintiq 24HD",       WACOM_PKGLEN_INTUOS,   104480, 65600, 2047,
+         63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0xF8 =
+       { "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS,   104480, 65600, 2047,
          63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0x3F =
        { "Wacom Cintiq 21UX",    WACOM_PKGLEN_INTUOS,    87200, 65600, 1023,
@@ -1653,6 +1874,9 @@ static const struct wacom_features wacom_features_0xF0 =
 static const struct wacom_features wacom_features_0xCC =
        { "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    87200, 65600, 2047,
          63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0xFA =
+       { "Wacom Cintiq 22HD",    WACOM_PKGLEN_INTUOS,    95840, 54260, 2047,
+         63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0x90 =
        { "Wacom ISDv4 90",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
          0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1670,34 +1894,49 @@ static const struct wacom_features wacom_features_0x9F =
          0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xE2 =
        { "Wacom ISDv4 E2",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,
-         0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 2 };
 static const struct wacom_features wacom_features_0xE3 =
        { "Wacom ISDv4 E3",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,
-         0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 2 };
+static const struct wacom_features wacom_features_0xE5 =
+       { "Wacom ISDv4 E5",       WACOM_PKGLEN_MTOUCH,    26202, 16325,  255,
+         0, MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xE6 =
        { "Wacom ISDv4 E6",       WACOM_PKGLEN_TPC2FG,    27760, 15694,  255,
-         0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+       .touch_max = 2 };
 static const struct wacom_features wacom_features_0xEC =
        { "Wacom ISDv4 EC",       WACOM_PKGLEN_GRAPHIRE,  25710, 14500,  255,
          0, TABLETPC,    WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xED =
+       { "Wacom ISDv4 ED",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
+         0, TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xEF =
+       { "Wacom ISDv4 EF",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
+         0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x47 =
        { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023,
          31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x84 =
        { "Wacom Wireless Receiver", WACOM_PKGLEN_WIRELESS, 0, 0, 0,
-         0, WIRELESS, 0, 0 };
+         0, WIRELESS, 0, 0, .touch_max = 16 };
 static const struct wacom_features wacom_features_0xD0 =
        { "Wacom Bamboo 2FG",     WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD1 =
        { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD2 =
        { "Wacom Bamboo Craft",   WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xD3 =
        { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN,     21648, 13700, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD4 =
        { "Wacom Bamboo Pen",     WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1706,28 +1945,35 @@ static const struct wacom_features wacom_features_0xD5 =
          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xD6 =
        { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN,   14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD7 =
        { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD8 =
        { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN,   21648, 13700, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 2 };
 static const struct wacom_features wacom_features_0xDA =
        { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN,  14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 2 };
 static struct wacom_features wacom_features_0xDB =
        { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN,  21648, 13700, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 2 };
 static const struct wacom_features wacom_features_0xDD =
         { "Wacom Bamboo Connect", WACOM_PKGLEN_BBPEN,     14720,  9200, 1023,
           31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xDE =
         { "Wacom Bamboo 16FG 4x5", WACOM_PKGLEN_BBPEN,    14720,  9200, 1023,
-          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 16 };
 static const struct wacom_features wacom_features_0xDF =
         { "Wacom Bamboo 16FG 6x8", WACOM_PKGLEN_BBPEN,    21648, 13700, 1023,
-          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 16 };
 static const struct wacom_features wacom_features_0x6004 =
        { "ISD-V4",               WACOM_PKGLEN_GRAPHIRE,  12800,  8000,  255,
          0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1801,6 +2047,11 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xBA) },
        { USB_DEVICE_WACOM(0xBB) },
        { USB_DEVICE_WACOM(0xBC) },
+       { USB_DEVICE_WACOM(0x26) },
+       { USB_DEVICE_WACOM(0x27) },
+       { USB_DEVICE_WACOM(0x28) },
+       { USB_DEVICE_WACOM(0x29) },
+       { USB_DEVICE_WACOM(0x2A) },
        { USB_DEVICE_WACOM(0x3F) },
        { USB_DEVICE_WACOM(0xC5) },
        { USB_DEVICE_WACOM(0xC6) },
@@ -1836,10 +2087,15 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x9F) },
        { USB_DEVICE_WACOM(0xE2) },
        { USB_DEVICE_WACOM(0xE3) },
+       { USB_DEVICE_WACOM(0xE5) },
        { USB_DEVICE_WACOM(0xE6) },
        { USB_DEVICE_WACOM(0xEC) },
+       { USB_DEVICE_WACOM(0xED) },
+       { USB_DEVICE_WACOM(0xEF) },
        { USB_DEVICE_WACOM(0x47) },
        { USB_DEVICE_WACOM(0xF4) },
+       { USB_DEVICE_WACOM(0xF8) },
+       { USB_DEVICE_WACOM(0xFA) },
        { USB_DEVICE_LENOVO(0x6004) },
        { }
 };