Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[cascardo/linux.git] / drivers / hid / wacom_wac.c
index bbe32d6..fa54d32 100644 (file)
@@ -45,6 +45,27 @@ static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
  */
 static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
 
+static void wacom_notify_battery(struct wacom_wac *wacom_wac,
+       int bat_capacity, bool bat_charging, bool bat_connected,
+       bool ps_connected)
+{
+       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+       bool changed = wacom_wac->battery_capacity != bat_capacity  ||
+                      wacom_wac->bat_charging     != bat_charging  ||
+                      wacom_wac->bat_connected    != bat_connected ||
+                      wacom_wac->ps_connected     != ps_connected;
+
+       if (changed) {
+               wacom_wac->battery_capacity = bat_capacity;
+               wacom_wac->bat_charging = bat_charging;
+               wacom_wac->bat_connected = bat_connected;
+               wacom_wac->ps_connected = ps_connected;
+
+               if (wacom->battery)
+                       power_supply_changed(wacom->battery);
+       }
+}
+
 static int wacom_penpartner_irq(struct wacom_wac *wacom)
 {
        unsigned char *data = wacom->data;
@@ -419,17 +440,26 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
                rw = (data[7] >> 2 & 0x07);
                battery_capacity = batcap_gr[rw];
                ps_connected = rw == 7;
-               if ((wacom->battery_capacity != battery_capacity) ||
-                   (wacom->ps_connected != ps_connected)) {
-                       wacom->battery_capacity = battery_capacity;
-                       wacom->ps_connected = ps_connected;
-                       wacom_notify_battery(wacom);
-               }
+               wacom_notify_battery(wacom, battery_capacity, ps_connected,
+                                    1, ps_connected);
        }
 exit:
        return retval;
 }
 
+static void wacom_intuos_schedule_prox_event(struct wacom_wac *wacom_wac)
+{
+       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+       struct hid_report *r;
+       struct hid_report_enum *re;
+
+       re = &(wacom->hdev->report_enum[HID_FEATURE_REPORT]);
+       r = re->report_id_hash[WACOM_REPORT_INTUOSREAD];
+       if (r) {
+               hid_hw_request(wacom->hdev, r, HID_REQ_GET_REPORT);
+       }
+}
+
 static int wacom_intuos_inout(struct wacom_wac *wacom)
 {
        struct wacom_features *features = &wacom->features;
@@ -551,12 +581,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
           (features->type == CINTIQ && !(data[1] & 0x40)))
                return 1;
 
-       if (wacom->shared) {
-               wacom->shared->stylus_in_proximity = true;
-
-               if (wacom->shared->touch_down)
-                       return 1;
-       }
+       wacom->shared->stylus_in_proximity = true;
+       if (wacom->shared->touch_down)
+               return 1;
 
        /* in Range while exiting */
        if (((data[1] & 0xfe) == 0x20) && wacom->reporting_data) {
@@ -568,8 +595,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
 
        /* Exit report */
        if ((data[1] & 0xfe) == 0x80) {
-               if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
-                       wacom->shared->stylus_in_proximity = false;
+               wacom->shared->stylus_in_proximity = false;
                wacom->reporting_data = false;
 
                /* don't report exit if we don't know the ID */
@@ -610,8 +636,11 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
        }
 
        /* don't report other events if we don't know the ID */
-       if (!wacom->id[idx])
+       if (!wacom->id[idx]) {
+               /* but reschedule a read of the current tool */
+               wacom_intuos_schedule_prox_event(wacom);
                return 1;
+       }
 
        return 0;
 }
@@ -1023,15 +1052,9 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
                bat_charging = (power_raw & 0x08) ? 1 : 0;
                ps_connected = (power_raw & 0x10) ? 1 : 0;
                battery_capacity = batcap_i4[power_raw & 0x07];
-               if ((wacom->battery_capacity != battery_capacity) ||
-                   (wacom->bat_charging != bat_charging) ||
-                   (wacom->ps_connected != ps_connected)) {
-                       wacom->battery_capacity = battery_capacity;
-                       wacom->bat_charging = bat_charging;
-                       wacom->ps_connected = ps_connected;
-                       wacom_notify_battery(wacom);
-               }
-
+               wacom_notify_battery(wacom, battery_capacity, bat_charging,
+                                    battery_capacity || bat_charging,
+                                    ps_connected);
                break;
        default:
                dev_dbg(wacom->input->dev.parent,
@@ -1042,6 +1065,28 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
        return 0;
 }
 
+static int wacom_wac_finger_count_touches(struct wacom_wac *wacom)
+{
+       struct input_dev *input = wacom->input;
+       unsigned touch_max = wacom->features.touch_max;
+       int count = 0;
+       int i;
+
+       /* non-HID_GENERIC single touch input doesn't call this routine */
+       if ((touch_max == 1) && (wacom->features.type == HID_GENERIC))
+               return wacom->hid_data.tipswitch &&
+                      !wacom->shared->stylus_in_proximity;
+
+       for (i = 0; i < input->mt->num_slots; i++) {
+               struct input_mt_slot *ps = &input->mt->slots[i];
+               int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
+               if (id >= 0)
+                       count++;
+       }
+
+       return count;
+}
+
 static int wacom_24hdt_irq(struct wacom_wac *wacom)
 {
        struct input_dev *input = wacom->input;
@@ -1052,7 +1097,6 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
        int num_contacts_left = 4; /* maximum contacts per packet */
        int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
        int y_offset = 2;
-       static int contact_with_no_pen_down_count = 0;
 
        if (wacom->features.type == WACOM_27QHDT) {
                current_num_contacts = data[63];
@@ -1065,10 +1109,8 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
         * First packet resets the counter since only the first
         * packet in series will have non-zero current_num_contacts.
         */
-       if (current_num_contacts) {
+       if (current_num_contacts)
                wacom->num_contacts_left = current_num_contacts;
-               contact_with_no_pen_down_count = 0;
-       }
 
        contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
 
@@ -1101,15 +1143,14 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
                                input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
                                input_report_abs(input, ABS_MT_ORIENTATION, w > h);
                        }
-                       contact_with_no_pen_down_count++;
                }
        }
-       input_mt_report_pointer_emulation(input, true);
+       input_mt_sync_frame(input);
 
        wacom->num_contacts_left -= contacts_to_send;
        if (wacom->num_contacts_left <= 0) {
                wacom->num_contacts_left = 0;
-               wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+               wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
        }
        return 1;
 }
@@ -1122,7 +1163,6 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
        int current_num_contacts = data[2];
        int contacts_to_send = 0;
        int x_offset = 0;
-       static int contact_with_no_pen_down_count = 0;
 
        /* MTTPC does not support Height and Width */
        if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
@@ -1132,10 +1172,8 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
         * First packet resets the counter since only the first
         * packet in series will have non-zero current_num_contacts.
         */
-       if (current_num_contacts) {
+       if (current_num_contacts)
                wacom->num_contacts_left = current_num_contacts;
-               contact_with_no_pen_down_count = 0;
-       }
 
        /* There are at most 5 contacts per packet */
        contacts_to_send = min(5, wacom->num_contacts_left);
@@ -1156,15 +1194,14 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
                        int y = get_unaligned_le16(&data[offset + x_offset + 9]);
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
-                       contact_with_no_pen_down_count++;
                }
        }
-       input_mt_report_pointer_emulation(input, true);
+       input_mt_sync_frame(input);
 
        wacom->num_contacts_left -= contacts_to_send;
        if (wacom->num_contacts_left <= 0) {
                wacom->num_contacts_left = 0;
-               wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+               wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
        }
        return 1;
 }
@@ -1173,7 +1210,6 @@ static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
 {
        struct input_dev *input = wacom->input;
        unsigned char *data = wacom->data;
-       int contact_with_no_pen_down_count = 0;
        int i;
 
        for (i = 0; i < 2; i++) {
@@ -1188,13 +1224,12 @@ static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
 
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
-                       contact_with_no_pen_down_count++;
                }
        }
-       input_mt_report_pointer_emulation(input, true);
+       input_mt_sync_frame(input);
 
        /* keep touch state for pen event */
-       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
 
        return 1;
 }
@@ -1522,29 +1557,6 @@ static int wacom_wac_finger_event(struct hid_device *hdev,
        return 0;
 }
 
-static int wacom_wac_finger_count_touches(struct hid_device *hdev)
-{
-       struct wacom *wacom = hid_get_drvdata(hdev);
-       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
-       struct input_dev *input = wacom_wac->input;
-       unsigned touch_max = wacom_wac->features.touch_max;
-       int count = 0;
-       int i;
-
-       if (touch_max == 1)
-               return wacom_wac->hid_data.tipswitch &&
-                      !wacom_wac->shared->stylus_in_proximity;
-
-       for (i = 0; i < input->mt->num_slots; i++) {
-               struct input_mt_slot *ps = &input->mt->slots[i];
-               int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
-               if (id >= 0)
-                       count++;
-       }
-
-       return count;
-}
-
 static void wacom_wac_finger_report(struct hid_device *hdev,
                struct hid_report *report)
 {
@@ -1559,7 +1571,7 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
        input_sync(input);
 
        /* keep touch state for pen event */
-       wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(hdev);
+       wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
 }
 
 void wacom_wac_usage_mapping(struct hid_device *hdev,
@@ -1619,7 +1631,6 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
        struct input_dev *pad_input = wacom->pad_input;
        unsigned char *data = wacom->data;
        int i;
-       int contact_with_no_pen_down_count = 0;
 
        if (data[0] != 0x02)
            return 0;
@@ -1647,22 +1658,21 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
                        }
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
-                       contact_with_no_pen_down_count++;
                }
        }
 
-       input_mt_report_pointer_emulation(input, true);
+       input_mt_sync_frame(input);
 
        input_report_key(pad_input, BTN_LEFT, (data[1] & 0x08) != 0);
        input_report_key(pad_input, BTN_FORWARD, (data[1] & 0x04) != 0);
        input_report_key(pad_input, BTN_BACK, (data[1] & 0x02) != 0);
        input_report_key(pad_input, BTN_RIGHT, (data[1] & 0x01) != 0);
-       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
 
        return 1;
 }
 
-static int wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data, int last_touch_count)
+static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
 {
        struct wacom_features *features = &wacom->features;
        struct input_dev *input = wacom->input;
@@ -1670,7 +1680,7 @@ static int wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data, in
        int slot = input_mt_get_slot_by_key(input, data[0]);
 
        if (slot < 0)
-               return 0;
+               return;
 
        touch = touch && !wacom->shared->stylus_in_proximity;
 
@@ -1702,9 +1712,7 @@ static int wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data, in
                input_report_abs(input, ABS_MT_POSITION_Y, y);
                input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
                input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
-               last_touch_count++;
        }
-       return last_touch_count;
 }
 
 static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
@@ -1729,7 +1737,6 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
        unsigned char *data = wacom->data;
        int count = data[1] & 0x07;
        int i;
-       int contact_with_no_pen_down_count = 0;
 
        if (data[0] != 0x02)
            return 0;
@@ -1740,15 +1747,13 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
                int msg_id = data[offset];
 
                if (msg_id >= 2 && msg_id <= 17)
-                       contact_with_no_pen_down_count = 
-                           wacom_bpt3_touch_msg(wacom, data + offset,
-                                                contact_with_no_pen_down_count);
+                       wacom_bpt3_touch_msg(wacom, data + offset);
                else if (msg_id == 128)
                        wacom_bpt3_button_msg(wacom, data + offset);
 
        }
-       input_mt_report_pointer_emulation(input, true);
-       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       input_mt_sync_frame(input);
+       wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
 
        return 1;
 }
@@ -1760,23 +1765,9 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
        unsigned char *data = wacom->data;
        int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0;
 
-       if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_USB)
+       if (data[0] != WACOM_REPORT_PENABLED)
            return 0;
 
-       if (data[0] == WACOM_REPORT_USB) {
-               if (features->type == INTUOSHT &&
-                   wacom->shared->touch_input &&
-                   features->touch_max) {
-                       input_report_switch(wacom->shared->touch_input,
-                                           SW_MUTE_DEVICE, data[8] & 0x40);
-                       input_sync(wacom->shared->touch_input);
-               }
-               return 0;
-       }
-
-       if (wacom->shared->touch_down)
-               return 0;
-
        prox = (data[1] & 0x20) == 0x20;
 
        /*
@@ -1789,17 +1780,21 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
         *
         * Hardware does report zero in most out-of-prox cases but not all.
         */
-       if (prox) {
-               if (!wacom->shared->stylus_in_proximity) {
-                       if (data[1] & 0x08) {
-                               wacom->tool[0] = BTN_TOOL_RUBBER;
-                               wacom->id[0] = ERASER_DEVICE_ID;
-                       } else {
-                               wacom->tool[0] = BTN_TOOL_PEN;
-                               wacom->id[0] = STYLUS_DEVICE_ID;
-                       }
-                       wacom->shared->stylus_in_proximity = true;
+       if (!wacom->shared->stylus_in_proximity) {
+               if (data[1] & 0x08) {
+                       wacom->tool[0] = BTN_TOOL_RUBBER;
+                       wacom->id[0] = ERASER_DEVICE_ID;
+               } else {
+                       wacom->tool[0] = BTN_TOOL_PEN;
+                       wacom->id[0] = STYLUS_DEVICE_ID;
                }
+       }
+
+       wacom->shared->stylus_in_proximity = prox;
+       if (wacom->shared->touch_down)
+               return 0;
+
+       if (prox) {
                x = le16_to_cpup((__le16 *)&data[2]);
                y = le16_to_cpup((__le16 *)&data[4]);
                p = le16_to_cpup((__le16 *)&data[6]);
@@ -1815,6 +1810,8 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
                pen = data[1] & 0x01;
                btn1 = data[1] & 0x02;
                btn2 = data[1] & 0x04;
+       } else {
+               wacom->id[0] = 0;
        }
 
        input_report_key(input, BTN_TOUCH, pen);
@@ -1826,11 +1823,6 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
        input_report_abs(input, ABS_PRESSURE, p);
        input_report_abs(input, ABS_DISTANCE, d);
 
-       if (!prox) {
-               wacom->id[0] = 0;
-               wacom->shared->stylus_in_proximity = false;
-       }
-
        input_report_key(input, wacom->tool[0], prox); /* PEN or RUBBER */
        input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
 
@@ -1849,6 +1841,91 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
        return 0;
 }
 
+static void wacom_bamboo_pad_pen_event(struct wacom_wac *wacom,
+               unsigned char *data)
+{
+       unsigned char prefix;
+
+       /*
+        * We need to reroute the event from the debug interface to the
+        * pen interface.
+        * We need to add the report ID to the actual pen report, so we
+        * temporary overwrite the first byte to prevent having to kzalloc/kfree
+        * and memcpy the report.
+        */
+       prefix = data[0];
+       data[0] = WACOM_REPORT_BPAD_PEN;
+
+       /*
+        * actually reroute the event.
+        * No need to check if wacom->shared->pen is valid, hid_input_report()
+        * will check for us.
+        */
+       hid_input_report(wacom->shared->pen, HID_INPUT_REPORT, data,
+                        WACOM_PKGLEN_PENABLED, 1);
+
+       data[0] = prefix;
+}
+
+static int wacom_bamboo_pad_touch_event(struct wacom_wac *wacom,
+               unsigned char *data)
+{
+       struct input_dev *input = wacom->input;
+       unsigned char *finger_data, prefix;
+       unsigned id;
+       int x, y;
+       bool valid;
+
+       prefix = data[0];
+
+       for (id = 0; id < wacom->features.touch_max; id++) {
+               valid = !!(prefix & BIT(id)) &&
+                       !wacom->shared->stylus_in_proximity;
+
+               input_mt_slot(input, id);
+               input_mt_report_slot_state(input, MT_TOOL_FINGER, valid);
+
+               if (!valid)
+                       continue;
+
+               finger_data = data + 1 + id * 3;
+               x = finger_data[0] | ((finger_data[1] & 0x0f) << 8);
+               y = (finger_data[2] << 4) | (finger_data[1] >> 4);
+
+               input_report_abs(input, ABS_MT_POSITION_X, x);
+               input_report_abs(input, ABS_MT_POSITION_Y, y);
+       }
+
+       input_mt_sync_frame(input);
+
+       input_report_key(input, BTN_LEFT, prefix & 0x40);
+       input_report_key(input, BTN_RIGHT, prefix & 0x80);
+
+       /* keep touch state for pen event */
+       wacom->shared->touch_down = !!prefix &&
+                                   !wacom->shared->stylus_in_proximity;
+
+       return 1;
+}
+
+static int wacom_bamboo_pad_irq(struct wacom_wac *wacom, size_t len)
+{
+       unsigned char *data = wacom->data;
+
+       if (!((len == WACOM_PKGLEN_BPAD_TOUCH) ||
+             (len == WACOM_PKGLEN_BPAD_TOUCH_USB)) ||
+           (data[0] != WACOM_REPORT_BPAD_TOUCH))
+               return 0;
+
+       if (data[1] & 0x01)
+               wacom_bamboo_pad_pen_event(wacom, &data[1]);
+
+       if (data[1] & 0x02)
+               return wacom_bamboo_pad_touch_event(wacom, &data[9]);
+
+       return 0;
+}
+
 static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
 {
        unsigned char *data = wacom->data;
@@ -1859,7 +1936,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
 
        connected = data[1] & 0x01;
        if (connected) {
-               int pid, battery, ps_connected;
+               int pid, battery, charging;
 
                if ((wacom->shared->type == INTUOSHT) &&
                    wacom->shared->touch_input &&
@@ -1871,30 +1948,63 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
 
                pid = get_unaligned_be16(&data[6]);
                battery = (data[5] & 0x3f) * 100 / 31;
-               ps_connected = !!(data[5] & 0x80);
+               charging = !!(data[5] & 0x80);
                if (wacom->pid != pid) {
                        wacom->pid = pid;
                        wacom_schedule_work(wacom);
                }
 
-               if (wacom->shared->type &&
-                   (battery != wacom->battery_capacity ||
-                    ps_connected != wacom->ps_connected)) {
-                       wacom->battery_capacity = battery;
-                       wacom->ps_connected = ps_connected;
-                       wacom->bat_charging = ps_connected &&
-                                               wacom->battery_capacity < 100;
-                       wacom_notify_battery(wacom);
-               }
+               if (wacom->shared->type)
+                       wacom_notify_battery(wacom, battery, charging, 1, 0);
+
        } else if (wacom->pid != 0) {
                /* disconnected while previously connected */
                wacom->pid = 0;
                wacom_schedule_work(wacom);
-               wacom->battery_capacity = 0;
-               wacom->bat_charging = 0;
-               wacom->ps_connected = 0;
+               wacom_notify_battery(wacom, 0, 0, 0, 0);
+       }
+
+       return 0;
+}
+
+static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
+{
+       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+       struct wacom_features *features = &wacom_wac->features;
+       unsigned char *data = wacom_wac->data;
+
+       if (data[0] != WACOM_REPORT_USB)
+               return 0;
+
+       if (features->type == INTUOSHT &&
+           wacom_wac->shared->touch_input &&
+           features->touch_max) {
+               input_report_switch(wacom_wac->shared->touch_input,
+                                   SW_MUTE_DEVICE, data[8] & 0x40);
+               input_sync(wacom_wac->shared->touch_input);
        }
 
+       if (data[9] & 0x02) { /* wireless module is attached */
+               int battery = (data[8] & 0x3f) * 100 / 31;
+               bool charging = !!(data[8] & 0x80);
+
+               wacom_notify_battery(wacom_wac, battery, charging,
+                                    battery || charging, 1);
+
+               if (!wacom->battery &&
+                   !(features->quirks & WACOM_QUIRK_BATTERY)) {
+                       features->quirks |= WACOM_QUIRK_BATTERY;
+                       INIT_WORK(&wacom->work, wacom_battery_work);
+                       wacom_schedule_work(wacom_wac);
+               }
+       }
+       else if ((features->quirks & WACOM_QUIRK_BATTERY) &&
+                wacom->battery) {
+               features->quirks &= ~WACOM_QUIRK_BATTERY;
+               INIT_WORK(&wacom->work, wacom_battery_work);
+               wacom_schedule_work(wacom_wac);
+               wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
+       }
        return 0;
 }
 
@@ -1967,6 +2077,8 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
        case INTUOSPL:
                if (len == WACOM_PKGLEN_BBTOUCH3)
                        sync = wacom_bpt3_touch(wacom_wac);
+               else if (wacom_wac->data[0] == WACOM_REPORT_USB)
+                       sync = wacom_status_irq(wacom_wac, len);
                else
                        sync = wacom_intuos_irq(wacom_wac);
                break;
@@ -1982,7 +2094,14 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 
        case BAMBOO_PT:
        case INTUOSHT:
-               sync = wacom_bpt_irq(wacom_wac, len);
+               if (wacom_wac->data[0] == WACOM_REPORT_USB)
+                       sync = wacom_status_irq(wacom_wac, len);
+               else
+                       sync = wacom_bpt_irq(wacom_wac, len);
+               break;
+
+       case BAMBOO_PAD:
+               sync = wacom_bamboo_pad_irq(wacom_wac, len);
                break;
 
        case WIRELESS:
@@ -2054,12 +2173,6 @@ void wacom_setup_device_quirks(struct wacom_features *features)
                features->y_max = 1023;
        }
 
-       /* these device have multiple inputs */
-       if (features->type >= WIRELESS ||
-           (features->type >= INTUOS5S && features->type <= INTUOSHT) ||
-           (features->oVid && features->oPid))
-               features->quirks |= WACOM_QUIRK_MULTI_INPUT;
-
        /* quirk for bamboo touch with 2 low res touches */
        if (features->type == BAMBOO_PT &&
            features->pktlen == WACOM_PKGLEN_BBTOUCH) {
@@ -2323,6 +2436,13 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
                                              0, 0);
                }
                break;
+       case BAMBOO_PAD:
+               __clear_bit(ABS_MISC, input_dev->absbit);
+               input_mt_init_slots(input_dev, features->touch_max,
+                                   INPUT_MT_POINTER);
+               __set_bit(BTN_LEFT, input_dev->keybit);
+               __set_bit(BTN_RIGHT, input_dev->keybit);
+               break;
        }
        return 0;
 }
@@ -2772,6 +2892,15 @@ static const struct wacom_features wacom_features_0x304 =
        { "Wacom Cintiq 13HD", 59152, 33448, 1023, 63,
          WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
+static const struct wacom_features wacom_features_0x333 =
+       { "Wacom Cintiq 13HD touch", 59152, 33448, 2047, 63,
+         WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x335 };
+static const struct wacom_features wacom_features_0x335 =
+       { "Wacom Cintiq 13HD touch", .type = WACOM_24HDT, /* Touch */
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x333, .touch_max = 10,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0xC7 =
        { "Wacom DTU1931", 37832, 30305, 511, 0,
          PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2976,6 +3105,12 @@ static const struct wacom_features wacom_features_0x30C =
        { "Wacom ISDv5 30C", .type = WACOM_24HDT, /* Touch */
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30A, .touch_max = 10,
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x318 =
+       { "Wacom USB Bamboo PAD", 4095, 4095, /* Touch */
+         .type = BAMBOO_PAD, 35, 48, .touch_max = 4 };
+static const struct wacom_features wacom_features_0x319 =
+       { "Wacom Wireless Bamboo PAD", 4095, 4095, /* Touch */
+         .type = BAMBOO_PAD, 35, 48, .touch_max = 4 };
 static const struct wacom_features wacom_features_0x323 =
        { "Wacom Intuos P M", 21600, 13500, 1023, 31,
          INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
@@ -2992,6 +3127,10 @@ static const struct wacom_features wacom_features_HID_ANY_ID =
        HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
        .driver_data = (kernel_ulong_t)&wacom_features_##prod
 
+#define I2C_DEVICE_WACOM(prod)                                         \
+       HID_DEVICE(BUS_I2C, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
+       .driver_data = (kernel_ulong_t)&wacom_features_##prod
+
 #define USB_DEVICE_LENOVO(prod)                                        \
        HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, prod),                     \
        .driver_data = (kernel_ulong_t)&wacom_features_##prod
@@ -3124,11 +3263,15 @@ const struct hid_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x314) },
        { USB_DEVICE_WACOM(0x315) },
        { USB_DEVICE_WACOM(0x317) },
+       { USB_DEVICE_WACOM(0x318) },
+       { USB_DEVICE_WACOM(0x319) },
        { USB_DEVICE_WACOM(0x323) },
        { USB_DEVICE_WACOM(0x32A) },
        { USB_DEVICE_WACOM(0x32B) },
        { USB_DEVICE_WACOM(0x32C) },
        { USB_DEVICE_WACOM(0x32F) },
+       { USB_DEVICE_WACOM(0x333) },
+       { USB_DEVICE_WACOM(0x335) },
        { USB_DEVICE_WACOM(0x4001) },
        { USB_DEVICE_WACOM(0x4004) },
        { USB_DEVICE_WACOM(0x5000) },
@@ -3136,6 +3279,7 @@ const struct hid_device_id wacom_ids[] = {
        { USB_DEVICE_LENOVO(0x6004) },
 
        { USB_DEVICE_WACOM(HID_ANY_ID) },
+       { I2C_DEVICE_WACOM(HID_ANY_ID) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, wacom_ids);