]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/hid/wacom_wac.c
Merge branches 'for-4.11/upstream-fixes', 'for-4.12/accutouch', 'for-4.12/cp2112...
[mirror_ubuntu-artful-kernel.git] / drivers / hid / wacom_wac.c
index 4aa3de9f1163b30eb64b4304f285a4167aef0cf0..4b225fb19a16842f635026d1b1023d5d1cf5068e 100644 (file)
@@ -773,131 +773,6 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
        return 0;
 }
 
-static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
-{
-       unsigned char *data = wacom_wac->data;
-       struct input_dev *input;
-       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
-       struct wacom_remote *remote = wacom->remote;
-       int bat_charging, bat_percent, touch_ring_mode;
-       __u32 serial;
-       int i, index = -1;
-       unsigned long flags;
-
-       if (data[0] != WACOM_REPORT_REMOTE) {
-               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));
-       input_report_key(input, BTN_3, (data[9] & 0x08));
-       input_report_key(input, BTN_4, (data[9] & 0x10));
-       input_report_key(input, BTN_5, (data[9] & 0x20));
-       input_report_key(input, BTN_6, (data[9] & 0x40));
-       input_report_key(input, BTN_7, (data[9] & 0x80));
-
-       input_report_key(input, BTN_8, (data[10] & 0x01));
-       input_report_key(input, BTN_9, (data[10] & 0x02));
-       input_report_key(input, BTN_A, (data[10] & 0x04));
-       input_report_key(input, BTN_B, (data[10] & 0x08));
-       input_report_key(input, BTN_C, (data[10] & 0x10));
-       input_report_key(input, BTN_X, (data[10] & 0x20));
-       input_report_key(input, BTN_Y, (data[10] & 0x40));
-       input_report_key(input, BTN_Z, (data[10] & 0x80));
-
-       input_report_key(input, BTN_BASE, (data[11] & 0x01));
-       input_report_key(input, BTN_BASE2, (data[11] & 0x02));
-
-       if (data[12] & 0x80)
-               input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
-       else
-               input_report_abs(input, ABS_WHEEL, 0);
-
-       bat_percent = data[7] & 0x7f;
-       bat_charging = !!(data[7] & 0x80);
-
-       if (data[9] | data[10] | (data[11] & 0x03) | data[12])
-               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-       else
-               input_report_abs(input, ABS_MISC, 0);
-
-       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 (remote->remotes[i].serial == serial)
-                       wacom->led.groups[i].select = touch_ring_mode;
-       }
-
-       __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
-                               bat_charging, 1, bat_charging);
-
-out:
-       spin_unlock_irqrestore(&remote->remote_lock, flags);
-       return 0;
-}
-
-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;
-       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;
-
-       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];
-
-               remote_data.remote[i].serial = serial;
-               remote_data.remote[i].connected = connected;
-       }
-
-       spin_lock_irqsave(&remote->remote_lock, flags);
-
-       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;
-       }
-
-       spin_unlock_irqrestore(&remote->remote_lock, flags);
-
-       wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
-}
-
 static inline bool report_touch_events(struct wacom_wac *wacom)
 {
        return (touch_arbitration ? !wacom->shared->stylus_in_proximity : 1);
@@ -1116,6 +991,131 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
        return 0;
 }
 
+static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
+{
+       unsigned char *data = wacom_wac->data;
+       struct input_dev *input;
+       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+       struct wacom_remote *remote = wacom->remote;
+       int bat_charging, bat_percent, touch_ring_mode;
+       __u32 serial;
+       int i, index = -1;
+       unsigned long flags;
+
+       if (data[0] != WACOM_REPORT_REMOTE) {
+               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));
+       input_report_key(input, BTN_3, (data[9] & 0x08));
+       input_report_key(input, BTN_4, (data[9] & 0x10));
+       input_report_key(input, BTN_5, (data[9] & 0x20));
+       input_report_key(input, BTN_6, (data[9] & 0x40));
+       input_report_key(input, BTN_7, (data[9] & 0x80));
+
+       input_report_key(input, BTN_8, (data[10] & 0x01));
+       input_report_key(input, BTN_9, (data[10] & 0x02));
+       input_report_key(input, BTN_A, (data[10] & 0x04));
+       input_report_key(input, BTN_B, (data[10] & 0x08));
+       input_report_key(input, BTN_C, (data[10] & 0x10));
+       input_report_key(input, BTN_X, (data[10] & 0x20));
+       input_report_key(input, BTN_Y, (data[10] & 0x40));
+       input_report_key(input, BTN_Z, (data[10] & 0x80));
+
+       input_report_key(input, BTN_BASE, (data[11] & 0x01));
+       input_report_key(input, BTN_BASE2, (data[11] & 0x02));
+
+       if (data[12] & 0x80)
+               input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
+       else
+               input_report_abs(input, ABS_WHEEL, 0);
+
+       bat_percent = data[7] & 0x7f;
+       bat_charging = !!(data[7] & 0x80);
+
+       if (data[9] | data[10] | (data[11] & 0x03) | data[12])
+               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+       else
+               input_report_abs(input, ABS_MISC, 0);
+
+       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 (remote->remotes[i].serial == serial)
+                       wacom->led.groups[i].select = touch_ring_mode;
+       }
+
+       __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
+                               bat_charging, 1, bat_charging);
+
+out:
+       spin_unlock_irqrestore(&remote->remote_lock, flags);
+       return 0;
+}
+
+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;
+       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;
+
+       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];
+
+               remote_data.remote[i].serial = serial;
+               remote_data.remote[i].connected = connected;
+       }
+
+       spin_lock_irqsave(&remote->remote_lock, flags);
+
+       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;
+       }
+
+       spin_unlock_irqrestore(&remote->remote_lock, flags);
+
+       wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
+}
+
 static int int_dist(int x1, int y1, int x2, int y2)
 {
        int x = x2 - x1;
@@ -1739,6 +1739,7 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
                features->device_type |= WACOM_DEVICETYPE_PAD;
                break;
        case WACOM_HID_WD_TOUCHONOFF:
+       case WACOM_HID_WD_MUTE_DEVICE:
                /*
                 * This usage, which is used to mute touch events, comes
                 * from the pad packet, but is reported on the touch
@@ -1768,6 +1769,26 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
                wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
                features->device_type |= WACOM_DEVICETYPE_PAD;
                break;
+       case WACOM_HID_WD_BUTTONCONFIG:
+               wacom_map_usage(input, usage, field, EV_KEY, KEY_BUTTONCONFIG, 0);
+               features->device_type |= WACOM_DEVICETYPE_PAD;
+               break;
+       case WACOM_HID_WD_ONSCREEN_KEYBOARD:
+               wacom_map_usage(input, usage, field, EV_KEY, KEY_ONSCREEN_KEYBOARD, 0);
+               features->device_type |= WACOM_DEVICETYPE_PAD;
+               break;
+       case WACOM_HID_WD_CONTROLPANEL:
+               wacom_map_usage(input, usage, field, EV_KEY, KEY_CONTROLPANEL, 0);
+               features->device_type |= WACOM_DEVICETYPE_PAD;
+               break;
+       case WACOM_HID_WD_MODE_CHANGE:
+               /* do not overwrite previous data */
+               if (!wacom_wac->has_mode_change) {
+                       wacom_wac->has_mode_change = true;
+                       wacom_wac->is_direct_mode = true;
+               }
+               features->device_type |= WACOM_DEVICETYPE_PAD;
+               break;
        }
 
        switch (equivalent_usage & 0xfffffff0) {
@@ -1811,12 +1832,13 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
        struct wacom_features *features = &wacom_wac->features;
        unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
        int i;
+       bool is_touch_on = value;
 
        /*
         * Avoid reporting this event and setting inrange_state if this usage
         * hasn't been mapped.
         */
-       if (!usage->type)
+       if (!usage->type && equivalent_usage != WACOM_HID_WD_MODE_CHANGE)
                return;
 
        if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) {
@@ -1830,14 +1852,28 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
                        input_event(input, usage->type, usage->code, 0);
                break;
 
+       case WACOM_HID_WD_MUTE_DEVICE:
+               if (wacom_wac->shared->touch_input && value) {
+                       wacom_wac->shared->is_touch_on = !wacom_wac->shared->is_touch_on;
+                       is_touch_on = wacom_wac->shared->is_touch_on;
+               }
+
+               /* fall through*/
        case WACOM_HID_WD_TOUCHONOFF:
                if (wacom_wac->shared->touch_input) {
                        input_report_switch(wacom_wac->shared->touch_input,
-                                           SW_MUTE_DEVICE, !value);
+                                           SW_MUTE_DEVICE, !is_touch_on);
                        input_sync(wacom_wac->shared->touch_input);
                }
                break;
 
+       case WACOM_HID_WD_MODE_CHANGE:
+               if (wacom_wac->is_direct_mode != value) {
+                       wacom_wac->is_direct_mode = value;
+                       wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_MODE_CHANGE);
+               }
+               break;
+
        case WACOM_HID_WD_BUTTONCENTER:
                for (i = 0; i < wacom->led.count; i++)
                        wacom_update_led(wacom, features->numbered_buttons,
@@ -1845,6 +1881,8 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
                 /* fall through*/
        default:
                input_event(input, usage->type, usage->code, value);
+               if (value)
+                       wacom_wac->hid_data.pad_input_event_flag = true;
                break;
        }
 }
@@ -1885,9 +1923,12 @@ static void wacom_wac_pad_report(struct hid_device *hdev,
        bool active = wacom_wac->hid_data.inrange_state != 0;
 
        /* report prox for expresskey events */
-       if (wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) {
+       if ((wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) &&
+           wacom_wac->hid_data.pad_input_event_flag) {
                input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
                input_sync(input);
+               if (!active)
+                       wacom_wac->hid_data.pad_input_event_flag = false;
        }
 
 }
@@ -1959,8 +2000,10 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
                input_set_capability(input, EV_KEY, BTN_TOOL_BRUSH);
                input_set_capability(input, EV_KEY, BTN_TOOL_PENCIL);
                input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH);
-               input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE);
-               input_set_capability(input, EV_KEY, BTN_TOOL_LENS);
+               if (!(features->device_type & WACOM_DEVICETYPE_DIRECT)) {
+                       input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE);
+                       input_set_capability(input, EV_KEY, BTN_TOOL_LENS);
+               }
                break;
        case WACOM_HID_WD_FINGERWHEEL:
                wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
@@ -2004,7 +2047,7 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
                return;
        case HID_DG_TOOLSERIALNUMBER:
                wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL);
-               wacom_wac->serial[0] |= value;
+               wacom_wac->serial[0] |= (__u32)value;
                return;
        case WACOM_HID_WD_SENSE:
                wacom_wac->hid_data.sense_state = value;
@@ -2174,6 +2217,16 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
                wacom_wac->hid_data.cc_index = field->index;
                wacom_wac->hid_data.cc_value_index = usage->usage_index;
                break;
+       case HID_DG_CONTACTID:
+               if ((field->logical_maximum - field->logical_minimum) < touch_max) {
+                       /*
+                        * The HID descriptor for G11 sensors leaves logical
+                        * maximum set to '1' despite it being a multitouch
+                        * device. Override to a sensible number.
+                        */
+                       field->logical_maximum = 255;
+               }
+               break;
        }
 }
 
@@ -2185,6 +2238,13 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
        bool prox = hid_data->tipswitch &&
                    report_touch_events(wacom_wac);
 
+       if (wacom_wac->shared->has_mute_touch_switch &&
+           !wacom_wac->shared->is_touch_on) {
+               if (!wacom_wac->shared->touch_down)
+                       return;
+               prox = 0;
+       }
+
        wacom_wac->hid_data.num_received++;
        if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected)
                return;
@@ -4115,7 +4175,7 @@ static const struct wacom_features wacom_features_0x300 =
          BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x301 =
        { "Wacom Bamboo One M", 21648, 13530, 1023, 31,
-         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x302 =
        { "Wacom Intuos PT S", 15200, 9500, 1023, 31,
          INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
@@ -4197,10 +4257,10 @@ static const struct wacom_features wacom_features_0x343 =
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
 static const struct wacom_features wacom_features_0x360 =
        { "Wacom Intuos Pro M", 44800, 29600, 8191, 63,
-         INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 };
+         INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
 static const struct wacom_features wacom_features_0x361 =
        { "Wacom Intuos Pro L", 62200, 43200, 8191, 63,
-         INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 };
+         INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
 
 static const struct wacom_features wacom_features_HID_ANY_ID =
        { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };