Merge tag 'for-linus-20161008' of git://git.infradead.org/linux-mtd
[cascardo/linux.git] / drivers / hid / wacom_wac.c
index 1eae13c..1cb7992 100644 (file)
  */
 #define WACOM_CONTACT_AREA_SCALE 2607
 
+static bool touch_arbitration = 1;
+module_param(touch_arbitration, bool, 0644);
+MODULE_PARM_DESC(touch_arbitration, " on (Y) off (N)");
+
 static void wacom_report_numbered_buttons(struct input_dev *input_dev,
                                int button_count, int mask);
 
@@ -48,25 +52,34 @@ 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_battery *battery,
+                                  int bat_capacity, bool bat_charging,
+                                  bool bat_connected, bool ps_connected)
+{
+       bool changed = battery->battery_capacity != bat_capacity  ||
+                      battery->bat_charging     != bat_charging  ||
+                      battery->bat_connected    != bat_connected ||
+                      battery->ps_connected     != ps_connected;
+
+       if (changed) {
+               battery->battery_capacity = bat_capacity;
+               battery->bat_charging = bat_charging;
+               battery->bat_connected = bat_connected;
+               battery->ps_connected = ps_connected;
+
+               if (battery->battery)
+                       power_supply_changed(battery->battery);
+       }
+}
+
 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);
-       }
+       __wacom_notify_battery(&wacom->battery, bat_capacity, bat_charging,
+                              bat_connected, ps_connected);
 }
 
 static int wacom_penpartner_irq(struct wacom_wac *wacom)
@@ -751,22 +764,37 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
 static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
 {
        unsigned char *data = wacom_wac->data;
-       struct input_dev *input = wacom_wac->pad_input;
+       struct input_dev *input;
        struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
-       struct wacom_features *features = &wacom_wac->features;
+       struct wacom_remote *remote = wacom->remote;
        int bat_charging, bat_percent, touch_ring_mode;
        __u32 serial;
-       int i;
+       int i, index = -1;
+       unsigned long flags;
 
        if (data[0] != WACOM_REPORT_REMOTE) {
-               dev_dbg(input->dev.parent,
-                       "%s: received unknown report #%d", __func__, data[0]);
+               hid_dbg(wacom->hdev, "%s: received unknown report #%d",
+                       __func__, data[0]);
                return 0;
        }
 
        serial = data[3] + (data[4] << 8) + (data[5] << 16);
        wacom_wac->id[0] = PAD_DEVICE_ID;
 
+       spin_lock_irqsave(&remote->remote_lock, flags);
+
+       for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+               if (remote->remotes[i].serial == serial) {
+                       index = i;
+                       break;
+               }
+       }
+
+       if (index < 0 || !remote->remotes[index].registered)
+               goto out;
+
+       input = remote->remotes[index].input;
+
        input_report_key(input, BTN_0, (data[9] & 0x01));
        input_report_key(input, BTN_1, (data[9] & 0x02));
        input_report_key(input, BTN_2, (data[9] & 0x04));
@@ -803,73 +831,69 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
 
        input_event(input, EV_MSC, MSC_SERIAL, serial);
 
+       input_sync(input);
+
        /*Which mode select (LED light) is currently on?*/
        touch_ring_mode = (data[11] & 0xC0) >> 6;
 
        for (i = 0; i < WACOM_MAX_REMOTES; i++) {
-               if (wacom_wac->serial[i] == serial)
-                       wacom->led.select[i] = touch_ring_mode;
-       }
-
-       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);
+               if (remote->remotes[i].serial == serial)
+                       wacom->led.groups[i].select = touch_ring_mode;
        }
 
-       wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1,
-                            bat_charging);
+       __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
+                               bat_charging, 1, bat_charging);
 
-       return 1;
+out:
+       spin_unlock_irqrestore(&remote->remote_lock, flags);
+       return 0;
 }
 
-static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
+static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
 {
        struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
        unsigned char *data = wacom_wac->data;
-       int i;
+       struct wacom_remote *remote = wacom->remote;
+       struct wacom_remote_data remote_data;
+       unsigned long flags;
+       int i, ret;
 
        if (data[0] != WACOM_REPORT_DEVICE_LIST)
-               return 0;
+               return;
+
+       memset(&remote_data, 0, sizeof(struct wacom_remote_data));
 
        for (i = 0; i < WACOM_MAX_REMOTES; i++) {
                int j = i * 6;
                int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
                bool connected = data[j+2];
 
-               if (connected) {
-                       int k;
+               remote_data.remote[i].serial = serial;
+               remote_data.remote[i].connected = connected;
+       }
 
-                       if (wacom_wac->serial[i] == serial)
-                               continue;
+       spin_lock_irqsave(&remote->remote_lock, flags);
 
-                       if (wacom_wac->serial[i]) {
-                               wacom_remote_destroy_attr_group(wacom,
-                                                       wacom_wac->serial[i]);
-                       }
+       ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
+       if (ret != sizeof(remote_data)) {
+               spin_unlock_irqrestore(&remote->remote_lock, flags);
+               hid_err(wacom->hdev, "Can't queue Remote status event.\n");
+               return;
+       }
 
-                       /* A remote can pair more than once with an EKR,
-                        * check to make sure this serial isn't already paired.
-                        */
-                       for (k = 0; k < WACOM_MAX_REMOTES; k++) {
-                               if (wacom_wac->serial[k] == serial)
-                                       break;
-                       }
+       spin_unlock_irqrestore(&remote->remote_lock, flags);
 
-                       if (k < WACOM_MAX_REMOTES) {
-                               wacom_wac->serial[i] = serial;
-                               continue;
-                       }
-                       wacom_remote_create_attr_group(wacom, serial, i);
+       wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
+}
 
-               } else if (wacom_wac->serial[i]) {
-                       wacom_remote_destroy_attr_group(wacom,
-                                                       wacom_wac->serial[i]);
-               }
-       }
+static inline bool report_touch_events(struct wacom_wac *wacom)
+{
+       return (touch_arbitration ? !wacom->shared->stylus_in_proximity : 1);
+}
 
-       return 0;
+static inline bool delay_pen_events(struct wacom_wac *wacom)
+{
+       return (wacom->shared->touch_down && touch_arbitration);
 }
 
 static int wacom_intuos_general(struct wacom_wac *wacom)
@@ -885,7 +909,7 @@ static int wacom_intuos_general(struct wacom_wac *wacom)
                data[0] != WACOM_REPORT_INTUOS_PEN)
                return 0;
 
-       if (wacom->shared->touch_down)
+       if (delay_pen_events(wacom))
                return 1;
 
        /* don't report events if we don't know the tool ID */
@@ -1145,7 +1169,7 @@ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom)
 
        if (touch_max == 1)
                return test_bit(BTN_TOUCH, input->key) &&
-                      !wacom->shared->stylus_in_proximity;
+                       report_touch_events(wacom);
 
        for (i = 0; i < input->mt->num_slots; i++) {
                struct input_mt_slot *ps = &input->mt->slots[i];
@@ -1186,7 +1210,7 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
 
        for (i = 0; i < contacts_to_send; i++) {
                int offset = (byte_per_packet * i) + 1;
-               bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity;
+               bool touch = (data[offset] & 0x1) && report_touch_events(wacom);
                int slot = input_mt_get_slot_by_key(input, data[offset + 1]);
 
                if (slot < 0)
@@ -1250,7 +1274,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
 
        for (i = 0; i < contacts_to_send; i++) {
                int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
-               bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity;
+               bool touch = (data[offset] & 0x1) && report_touch_events(wacom);
                int id = get_unaligned_le16(&data[offset + 1]);
                int slot = input_mt_get_slot_by_key(input, id);
 
@@ -1284,7 +1308,7 @@ static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
 
        for (i = 0; i < 2; i++) {
                int p = data[1] & (1 << i);
-               bool touch = p && !wacom->shared->stylus_in_proximity;
+               bool touch = p && report_touch_events(wacom);
 
                input_mt_slot(input, i);
                input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
@@ -1308,7 +1332,7 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
 {
        unsigned char *data = wacom->data;
        struct input_dev *input = wacom->touch_input;
-       bool prox = !wacom->shared->stylus_in_proximity;
+       bool prox = report_touch_events(wacom);
        int x = 0, y = 0;
 
        if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
@@ -1353,8 +1377,10 @@ static int wacom_tpc_pen(struct wacom_wac *wacom)
        /* keep pen state for touch events */
        wacom->shared->stylus_in_proximity = prox;
 
-       /* send pen events only when touch is up or forced out */
-       if (!wacom->shared->touch_down) {
+       /* send pen events only when touch is up or forced out
+        * or touch arbitration is off
+        */
+       if (!delay_pen_events(wacom)) {
                input_report_key(input, BTN_STYLUS, data[1] & 0x02);
                input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
                input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
@@ -1496,8 +1522,10 @@ static int wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field,
                return 0;
        }
 
-       /* send pen events only when touch is up or forced out */
-       if (!usage->type || wacom_wac->shared->touch_down)
+       /* send pen events only when touch is up or forced out
+        * or touch arbitration is off
+        */
+       if (!usage->type || delay_pen_events(wacom_wac))
                return 0;
 
        input_event(input, usage->type, usage->code, value);
@@ -1527,8 +1555,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
        /* keep pen state for touch events */
        wacom_wac->shared->stylus_in_proximity = prox;
 
-       /* send pen events only when touch is up or forced out */
-       if (!wacom_wac->shared->touch_down) {
+       if (!delay_pen_events(wacom_wac)) {
                input_report_key(input, BTN_TOUCH,
                                wacom_wac->hid_data.tipswitch);
                input_report_key(input, wacom_wac->tool[0], prox);
@@ -1544,13 +1571,11 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
 {
        struct wacom *wacom = hid_get_drvdata(hdev);
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
-       struct wacom_features *features = &wacom_wac->features;
        struct input_dev *input = wacom_wac->touch_input;
        unsigned touch_max = wacom_wac->features.touch_max;
 
        switch (usage->hid) {
        case HID_GD_X:
-               features->last_slot_field = usage->hid;
                if (touch_max == 1)
                        wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4);
                else
@@ -1558,7 +1583,6 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
                                        ABS_MT_POSITION_X, 4);
                break;
        case HID_GD_Y:
-               features->last_slot_field = usage->hid;
                if (touch_max == 1)
                        wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4);
                else
@@ -1567,22 +1591,11 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
                break;
        case HID_DG_WIDTH:
        case HID_DG_HEIGHT:
-               features->last_slot_field = usage->hid;
                wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0);
                wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0);
                input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
                break;
-       case HID_DG_CONTACTID:
-               features->last_slot_field = usage->hid;
-               break;
-       case HID_DG_INRANGE:
-               features->last_slot_field = usage->hid;
-               break;
-       case HID_DG_INVERT:
-               features->last_slot_field = usage->hid;
-               break;
        case HID_DG_TIPSWITCH:
-               features->last_slot_field = usage->hid;
                wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
                break;
        case HID_DG_CONTACTCOUNT:
@@ -1599,7 +1612,7 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
        struct hid_data *hid_data = &wacom_wac->hid_data;
        bool mt = wacom_wac->features.touch_max > 1;
        bool prox = hid_data->tipswitch &&
-                   !wacom_wac->shared->stylus_in_proximity;
+                   report_touch_events(wacom_wac);
 
        wacom_wac->hid_data.num_received++;
        if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected)
@@ -1660,7 +1673,7 @@ static int wacom_wac_finger_event(struct hid_device *hdev,
 
 
        if (usage->usage_index + 1 == field->report_count) {
-               if (usage->hid == wacom_wac->features.last_slot_field)
+               if (usage->hid == wacom_wac->hid_data.last_slot_field)
                        wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
        }
 
@@ -1673,31 +1686,35 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
        struct wacom *wacom = hid_get_drvdata(hdev);
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
        struct hid_data* hid_data = &wacom_wac->hid_data;
+       int i;
 
-       if (hid_data->cc_report != 0 &&
-           hid_data->cc_report != report->id) {
-               int i;
-
-               hid_data->cc_report = report->id;
-               hid_data->cc_index = -1;
-               hid_data->cc_value_index = -1;
-
-               for (i = 0; i < report->maxfield; i++) {
-                       struct hid_field *field = report->field[i];
-                       int j;
-
-                       for (j = 0; j < field->maxusage; j++) {
-                               if (field->usage[j].hid == HID_DG_CONTACTCOUNT) {
-                                       hid_data->cc_index = i;
-                                       hid_data->cc_value_index = j;
-
-                                       /* break */
-                                       i = report->maxfield;
-                                       j = field->maxusage;
-                               }
+       for (i = 0; i < report->maxfield; i++) {
+               struct hid_field *field = report->field[i];
+               int j;
+
+               for (j = 0; j < field->maxusage; j++) {
+                       struct hid_usage *usage = &field->usage[j];
+
+                       switch (usage->hid) {
+                       case HID_GD_X:
+                       case HID_GD_Y:
+                       case HID_DG_WIDTH:
+                       case HID_DG_HEIGHT:
+                       case HID_DG_CONTACTID:
+                       case HID_DG_INRANGE:
+                       case HID_DG_INVERT:
+                       case HID_DG_TIPSWITCH:
+                               hid_data->last_slot_field = usage->hid;
+                               break;
+                       case HID_DG_CONTACTCOUNT:
+                               hid_data->cc_report = report->id;
+                               hid_data->cc_index = i;
+                               hid_data->cc_value_index = j;
+                               break;
                        }
                }
        }
+
        if (hid_data->cc_report != 0 &&
            hid_data->cc_index >= 0) {
                struct hid_field *field = report->field[hid_data->cc_index];
@@ -1740,10 +1757,10 @@ void wacom_wac_usage_mapping(struct hid_device *hdev,
 {
        struct wacom *wacom = hid_get_drvdata(hdev);
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+       struct wacom_features *features = &wacom_wac->features;
 
        /* currently, only direct devices have proper hid report descriptors */
-       __set_bit(INPUT_PROP_DIRECT, wacom_wac->pen_input->propbit);
-       __set_bit(INPUT_PROP_DIRECT, wacom_wac->touch_input->propbit);
+       features->device_type |= WACOM_DEVICETYPE_DIRECT;
 
        if (WACOM_PEN_FIELD(field))
                return wacom_wac_pen_usage_mapping(hdev, field, usage);
@@ -1825,15 +1842,8 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
 
        for (i = 0; i < 2; i++) {
                int offset = (data[1] & 0x80) ? (8 * i) : (9 * i);
-               bool touch = data[offset + 3] & 0x80;
-
-               /*
-                * Touch events need to be disabled while stylus is
-                * in proximity because user's hand is resting on touchpad
-                * and sending unwanted events.  User expects tablet buttons
-                * to continue working though.
-                */
-               touch = touch && !wacom->shared->stylus_in_proximity;
+               bool touch = report_touch_events(wacom)
+                          && (data[offset + 3] & 0x80);
 
                input_mt_slot(input, i);
                input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
@@ -1870,7 +1880,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
        if (slot < 0)
                return;
 
-       touch = touch && !wacom->shared->stylus_in_proximity;
+       touch = touch && report_touch_events(wacom);
 
        input_mt_slot(input, slot);
        input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
@@ -1942,7 +1952,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
        }
 
        /* only update touch if we actually have a touchpad and touch data changed */
-       if (wacom->touch_registered && touch_changed) {
+       if (wacom->touch_input && touch_changed) {
                input_mt_sync_frame(wacom->touch_input);
                wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
        }
@@ -1983,7 +1993,7 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
        }
 
        wacom->shared->stylus_in_proximity = prox;
-       if (wacom->shared->touch_down)
+       if (delay_pen_events(wacom))
                return 0;
 
        if (prox) {
@@ -2077,7 +2087,7 @@ static int wacom_bamboo_pad_touch_event(struct wacom_wac *wacom,
 
        for (id = 0; id < wacom->features.touch_max; id++) {
                valid = !!(prefix & BIT(id)) &&
-                       !wacom->shared->stylus_in_proximity;
+                       report_touch_events(wacom);
 
                input_mt_slot(input, id);
                input_mt_report_slot_state(input, MT_TOOL_FINGER, valid);
@@ -2099,8 +2109,7 @@ static int wacom_bamboo_pad_touch_event(struct wacom_wac *wacom,
        input_report_key(input, BTN_RIGHT, prefix & 0x80);
 
        /* keep touch state for pen event */
-       wacom->shared->touch_down = !!prefix &&
-                                   !wacom->shared->stylus_in_proximity;
+       wacom->shared->touch_down = !!prefix && report_touch_events(wacom);
 
        return 1;
 }
@@ -2149,16 +2158,15 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
                charging = !!(data[5] & 0x80);
                if (wacom->pid != pid) {
                        wacom->pid = pid;
-                       wacom_schedule_work(wacom);
+                       wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
                }
 
-               if (wacom->shared->type)
-                       wacom_notify_battery(wacom, battery, charging, 1, 0);
+               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_schedule_work(wacom, WACOM_WORKER_WIRELESS);
                wacom_notify_battery(wacom, 0, 0, 0, 0);
        }
 
@@ -2190,18 +2198,16 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
                wacom_notify_battery(wacom_wac, battery, charging,
                                     battery || charging, 1);
 
-               if (!wacom->battery &&
+               if (!wacom->battery.battery &&
                    !(features->quirks & WACOM_QUIRK_BATTERY)) {
                        features->quirks |= WACOM_QUIRK_BATTERY;
-                       INIT_WORK(&wacom->work, wacom_battery_work);
-                       wacom_schedule_work(wacom_wac);
+                       wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
                }
        }
        else if ((features->quirks & WACOM_QUIRK_BATTERY) &&
-                wacom->battery) {
+                wacom->battery.battery) {
                features->quirks &= ~WACOM_QUIRK_BATTERY;
-               INIT_WORK(&wacom->work, wacom_battery_work);
-               wacom_schedule_work(wacom_wac);
+               wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
                wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
        }
        return 0;
@@ -2312,8 +2318,9 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
                break;
 
        case REMOTE:
+               sync = false;
                if (wacom_wac->data[0] == WACOM_REPORT_DEVICE_LIST)
-                       sync = wacom_remote_status_irq(wacom_wac, len);
+                       wacom_remote_status_irq(wacom_wac, len);
                else
                        sync = wacom_remote_irq(wacom_wac, len);
                break;
@@ -2451,6 +2458,33 @@ void wacom_setup_device_quirks(struct wacom *wacom)
        if (features->type == REMOTE)
                features->device_type = WACOM_DEVICETYPE_PAD;
 
+       switch (features->type) {
+       case PL:
+       case DTU:
+       case DTUS:
+       case DTUSX:
+       case WACOM_21UX2:
+       case WACOM_22HD:
+       case DTK:
+       case WACOM_24HD:
+       case WACOM_27QHD:
+       case CINTIQ_HYBRID:
+       case CINTIQ_COMPANION_2:
+       case CINTIQ:
+       case WACOM_BEE:
+       case WACOM_13HD:
+       case WACOM_24HDT:
+       case WACOM_27QHDT:
+       case TABLETPC:
+       case TABLETPCE:
+       case TABLETPC2FG:
+       case MTSCREEN:
+       case MTTPC:
+       case MTTPC_B:
+               features->device_type |= WACOM_DEVICETYPE_DIRECT;
+               break;
+       }
+
        if (wacom->hdev->bus == BUS_BLUETOOTH)
                features->quirks |= WACOM_QUIRK_BATTERY;
 
@@ -2469,6 +2503,9 @@ void wacom_setup_device_quirks(struct wacom *wacom)
                        features->quirks |= WACOM_QUIRK_BATTERY;
                }
        }
+
+       if (features->type == REMOTE)
+               features->device_type |= WACOM_DEVICETYPE_WL_MONITOR;
 }
 
 int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
@@ -2481,6 +2518,11 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
        if (!(features->device_type & WACOM_DEVICETYPE_PEN))
                return -ENODEV;
 
+       if (features->device_type & WACOM_DEVICETYPE_DIRECT)
+               __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+       else
+               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
        if (features->type == HID_GENERIC)
                /* setup has already been done */
                return 0;
@@ -2499,7 +2541,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
        input_abs_set_res(input_dev, ABS_X, features->x_resolution);
        input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
 
-
        switch (features->type) {
        case GRAPHIRE_BT:
                __clear_bit(ABS_MISC, input_dev->absbit);
@@ -2523,8 +2564,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
                __set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
                __set_bit(BTN_STYLUS, input_dev->keybit);
                __set_bit(BTN_STYLUS2, input_dev->keybit);
-
-               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
                break;
 
        case WACOM_27QHD:
@@ -2539,7 +2578,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
        case CINTIQ_COMPANION_2:
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                input_abs_set_res(input_dev, ABS_Z, 287);
-               __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
                wacom_setup_cintiq(wacom_wac);
                break;
 
@@ -2555,8 +2593,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
                /* fall through */
 
        case INTUOS:
-               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-
                wacom_setup_intuos(wacom_wac);
                break;
 
@@ -2566,8 +2602,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
        case INTUOSPL:
        case INTUOS5S:
        case INTUOSPS:
-               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-
                input_set_abs_params(input_dev, ABS_DISTANCE, 0,
                                      features->distance_max,
                                      features->distance_fuzz, 0);
@@ -2597,8 +2631,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
                __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
                __set_bit(BTN_STYLUS, input_dev->keybit);
                __set_bit(BTN_STYLUS2, input_dev->keybit);
-
-               __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
                break;
 
        case PTU:
@@ -2609,16 +2641,12 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
                __set_bit(BTN_TOOL_PEN, input_dev->keybit);
                __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
                __set_bit(BTN_STYLUS, input_dev->keybit);
-
-               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
                break;
 
        case INTUOSHT:
        case BAMBOO_PT:
        case BAMBOO_PEN:
        case INTUOSHT2:
-               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-
                if (features->type == INTUOSHT2) {
                        wacom_setup_basic_pro_pen(wacom_wac);
                } else {
@@ -2649,6 +2677,11 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
        if (!(features->device_type & WACOM_DEVICETYPE_TOUCH))
                return -ENODEV;
 
+       if (features->device_type & WACOM_DEVICETYPE_DIRECT)
+               __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+       else
+               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
        if (features->type == HID_GENERIC)
                /* setup has already been done */
                return 0;
@@ -2683,8 +2716,6 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
        case INTUOSPL:
        case INTUOS5S:
        case INTUOSPS:
-               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-
                input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0);
                input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, features->y_max, 0, 0);
                input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
@@ -2707,7 +2738,6 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
 
        case TABLETPC:
        case TABLETPCE:
-               __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
                break;
 
        case INTUOSHT:
@@ -2752,11 +2782,105 @@ static void wacom_setup_numbered_buttons(struct input_dev *input_dev,
                __set_bit(BTN_BASE + (i-16), input_dev->keybit);
 }
 
+static void wacom_24hd_update_leds(struct wacom *wacom, int mask, int group)
+{
+       struct wacom_led *led;
+       int i;
+       bool updated = false;
+
+       /*
+        * 24HD has LED group 1 to the left and LED group 0 to the right.
+        * So group 0 matches the second half of the buttons and thus the mask
+        * needs to be shifted.
+        */
+       if (group == 0)
+               mask >>= 8;
+
+       for (i = 0; i < 3; i++) {
+               led = wacom_led_find(wacom, group, i);
+               if (!led) {
+                       hid_err(wacom->hdev, "can't find LED %d in group %d\n",
+                               i, group);
+                       continue;
+               }
+               if (!updated && mask & BIT(i)) {
+                       led->held = true;
+                       led_trigger_event(&led->trigger, LED_FULL);
+               } else {
+                       led->held = false;
+               }
+       }
+}
+
+static bool wacom_is_led_toggled(struct wacom *wacom, int button_count,
+                                int mask, int group)
+{
+       int button_per_group;
+
+       /*
+        * 21UX2 has LED group 1 to the left and LED group 0
+        * to the right. We need to reverse the group to match this
+        * historical behavior.
+        */
+       if (wacom->wacom_wac.features.type == WACOM_21UX2)
+               group = 1 - group;
+
+       button_per_group = button_count/wacom->led.count;
+
+       return mask & (1 << (group * button_per_group));
+}
+
+static void wacom_update_led(struct wacom *wacom, int button_count, int mask,
+                            int group)
+{
+       struct wacom_led *led, *next_led;
+       int cur;
+       bool pressed;
+
+       if (wacom->wacom_wac.features.type == WACOM_24HD)
+               return wacom_24hd_update_leds(wacom, mask, group);
+
+       pressed = wacom_is_led_toggled(wacom, button_count, mask, group);
+       cur = wacom->led.groups[group].select;
+
+       led = wacom_led_find(wacom, group, cur);
+       if (!led) {
+               hid_err(wacom->hdev, "can't find current LED %d in group %d\n",
+                       cur, group);
+               return;
+       }
+
+       if (!pressed) {
+               led->held = false;
+               return;
+       }
+
+       if (led->held && pressed)
+               return;
+
+       next_led = wacom_led_next(wacom, led);
+       if (!next_led) {
+               hid_err(wacom->hdev, "can't find next LED in group %d\n",
+                       group);
+               return;
+       }
+       if (next_led == led)
+               return;
+
+       next_led->held = true;
+       led_trigger_event(&next_led->trigger,
+                         wacom_leds_brightness_get(next_led));
+}
+
 static void wacom_report_numbered_buttons(struct input_dev *input_dev,
                                int button_count, int mask)
 {
+       struct wacom *wacom = input_get_drvdata(input_dev);
        int i;
 
+       for (i = 0; i < wacom->led.count; i++)
+               wacom_update_led(wacom,  button_count, mask, i);
+
        for (i = 0; i < button_count && i < 10; i++)
                input_report_key(input_dev, BTN_0 + i, mask & (1 << i));
        for (i = 10; i < button_count && i < 16; i++)
@@ -2773,6 +2897,9 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
        if (!(features->device_type & WACOM_DEVICETYPE_PAD))
                return -ENODEV;
 
+       if (features->type == REMOTE && input_dev == wacom_wac->pad_input)
+               return -ENODEV;
+
        input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 
        /* kept for making legacy xf86-input-wacom working with the wheels */
@@ -3403,7 +3530,7 @@ static const struct wacom_features wacom_features_0x343 =
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
 
 static const struct wacom_features wacom_features_HID_ANY_ID =
-       { "Wacom HID", .type = HID_GENERIC };
+       { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
 
 #define USB_DEVICE_WACOM(prod)                                         \
        HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\