Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 5 Oct 2017 17:28:12 +0000 (10:28 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 5 Oct 2017 17:28:12 +0000 (10:28 -0700)
Pull HID subsystem fixes from Jiri Kosina:

 - buffer management size fix for i2c-hid driver, from Adrian Salido

 - tool ID regression fixes for Wacom driver from Jason Gerecke

 - a few small assorted fixes and a few device ID additions

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid:
  Revert "HID: multitouch: Support ALPS PTP stick with pid 0x120A"
  HID: hidraw: fix power sequence when closing device
  HID: wacom: Always increment hdev refcount within wacom_get_hdev_data
  HID: wacom: generic: Clear ABS_MISC when tool leaves proximity
  HID: wacom: generic: Send MSC_SERIAL and ABS_MISC when leaving prox
  HID: i2c-hid: allocate hid buffers for real worst case
  HID: rmi: Make sure the HID device is opened on resume
  HID: multitouch: Support ALPS PTP stick with pid 0x120A
  HID: multitouch: support buttons and trackpoint on Lenovo X1 Tab Gen2
  HID: wacom: Correct coordinate system of touchring and pen twist
  HID: wacom: Properly report negative values from Intuos Pro 2 Bluetooth
  HID: multitouch: Fix system-control buttons not working
  HID: add multi-input quirk for IDC6680 touchscreen
  HID: wacom: leds: Don't try to control the EKR's read-only LEDs
  HID: wacom: bits shifted too much for 9th and 10th buttons

drivers/hid/hid-ids.h
drivers/hid/hid-multitouch.c
drivers/hid/hid-rmi.c
drivers/hid/hidraw.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c

index b397a14ab9703b259d7b258ebcfdc9d582b31b07..a98919199858717ecd173ba2ef04f014edcb109f 100644 (file)
 #define USB_VENDOR_ID_IDEACOM          0x1cb6
 #define USB_DEVICE_ID_IDEACOM_IDC6650  0x6650
 #define USB_DEVICE_ID_IDEACOM_IDC6651  0x6651
+#define USB_DEVICE_ID_IDEACOM_IDC6680  0x6680
 
 #define USB_VENDOR_ID_ILITEK           0x222a
 #define USB_DEVICE_ID_ILITEK_MULTITOUCH        0x0001
 #define USB_DEVICE_ID_LENOVO_CBTKBD    0x6048
 #define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067
 #define USB_DEVICE_ID_LENOVO_X1_COVER  0x6085
+#define USB_DEVICE_ID_LENOVO_X1_TAB    0x60a3
 
 #define USB_VENDOR_ID_LG               0x1fd2
 #define USB_DEVICE_ID_LG_MULTITOUCH    0x0064
index 440b999304a554309c208999ae2be053ec218d32..9e8c4d2ba11d2cc7c2559f34dc46fe646640e131 100644 (file)
@@ -930,6 +930,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
            field->application != HID_DG_PEN &&
            field->application != HID_DG_TOUCHPAD &&
            field->application != HID_GD_KEYBOARD &&
+           field->application != HID_GD_SYSTEM_CONTROL &&
            field->application != HID_CP_CONSUMER_CONTROL &&
            field->application != HID_GD_WIRELESS_RADIO_CTLS &&
            !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
@@ -1419,6 +1420,12 @@ static const struct hid_device_id mt_devices[] = {
                        USB_VENDOR_ID_ALPS_JP,
                        HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) },
 
+       /* Lenovo X1 TAB Gen 2 */
+       { .driver_data = MT_CLS_WIN_8_DUAL,
+               HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
+                          USB_VENDOR_ID_LENOVO,
+                          USB_DEVICE_ID_LENOVO_X1_TAB) },
+
        /* Anton devices */
        { .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
                MT_USB_DEVICE(USB_VENDOR_ID_ANTON,
index 5b40c26145993fafa51530dcb573bad0e971fb89..ef241d66562e00950e8979ef4fd0633fd4efdca3 100644 (file)
@@ -436,17 +436,24 @@ static int rmi_post_resume(struct hid_device *hdev)
        if (!(data->device_flags & RMI_DEVICE))
                return 0;
 
-       ret = rmi_reset_attn_mode(hdev);
+       /* Make sure the HID device is ready to receive events */
+       ret = hid_hw_open(hdev);
        if (ret)
                return ret;
 
+       ret = rmi_reset_attn_mode(hdev);
+       if (ret)
+               goto out;
+
        ret = rmi_driver_resume(rmi_dev, false);
        if (ret) {
                hid_warn(hdev, "Failed to resume device: %d\n", ret);
-               return ret;
+               goto out;
        }
 
-       return 0;
+out:
+       hid_hw_close(hdev);
+       return ret;
 }
 #endif /* CONFIG_PM */
 
index ec530454e6f68789fe57444fba14eb1daae94e2e..5fbe0f81ab2ebd2c972237fa1be2bc3b544afee8 100644 (file)
@@ -337,8 +337,8 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit)
                        kfree(hidraw);
                } else {
                        /* close device for last reader */
-                       hid_hw_power(hidraw->hid, PM_HINT_NORMAL);
                        hid_hw_close(hidraw->hid);
+                       hid_hw_power(hidraw->hid, PM_HINT_NORMAL);
                }
        }
 }
index 77396145d2d093af60e44c825ffaabd25f9b68a1..9145c2129a967464e1e7ed8978dbe53c6db9e86e 100644 (file)
@@ -543,7 +543,8 @@ static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size)
 {
        /* the worst case is computed from the set_report command with a
         * reportID > 15 and the maximum report length */
-       int args_len = sizeof(__u8) + /* optional ReportID byte */
+       int args_len = sizeof(__u8) + /* ReportID */
+                      sizeof(__u8) + /* optional ReportID byte */
                       sizeof(__u16) + /* data register */
                       sizeof(__u16) + /* size of the report */
                       report_size; /* report */
index a83fa76655b94f6ab8461f167748f785d1a1cebc..f489a5cfcb48cf5216a532091482ac669786e61d 100644 (file)
@@ -99,6 +99,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
+       { USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS, HID_QUIRK_NOGET },
index e82a696a1d07ca97df04371c00dc5dc95fbafec9..906e654fb0ba42fe85b49e3813beebabe86d7b3e 100644 (file)
@@ -668,8 +668,10 @@ static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
 
        /* Try to find an already-probed interface from the same device */
        list_for_each_entry(data, &wacom_udev_list, list) {
-               if (compare_device_paths(hdev, data->dev, '/'))
+               if (compare_device_paths(hdev, data->dev, '/')) {
+                       kref_get(&data->kref);
                        return data;
+               }
        }
 
        /* Fallback to finding devices that appear to be "siblings" */
@@ -766,6 +768,9 @@ static int wacom_led_control(struct wacom *wacom)
        if (!wacom->led.groups)
                return -ENOTSUPP;
 
+       if (wacom->wacom_wac.features.type == REMOTE)
+               return -ENOTSUPP;
+
        if (wacom->wacom_wac.pid) { /* wireless connected */
                report_id = WAC_CMD_WL_LED_CONTROL;
                buf_size = 13;
index bb17d7bbefd3e7bf033344e7e1bc6b5d5228fd27..aa692e28b2cd60e52bbae7dcb93454fa145ee69a 100644 (file)
@@ -567,8 +567,8 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
                                keys = data[9] & 0x07;
                        }
                } else {
-                       buttons = ((data[6] & 0x10) << 10) |
-                                 ((data[5] & 0x10) << 9)  |
+                       buttons = ((data[6] & 0x10) << 5)  |
+                                 ((data[5] & 0x10) << 4)  |
                                  ((data[6] & 0x0F) << 4)  |
                                  (data[5] & 0x0F);
                }
@@ -1227,11 +1227,17 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
                        continue;
 
                if (range) {
+                       /* Fix rotation alignment: userspace expects zero at left */
+                       int16_t rotation = (int16_t)get_unaligned_le16(&frame[9]);
+                       rotation += 1800/4;
+                       if (rotation > 899)
+                               rotation -= 1800;
+
                        input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
                        input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
-                       input_report_abs(pen_input, ABS_TILT_X, frame[7]);
-                       input_report_abs(pen_input, ABS_TILT_Y, frame[8]);
-                       input_report_abs(pen_input, ABS_Z, get_unaligned_le16(&frame[9]));
+                       input_report_abs(pen_input, ABS_TILT_X, (char)frame[7]);
+                       input_report_abs(pen_input, ABS_TILT_Y, (char)frame[8]);
+                       input_report_abs(pen_input, ABS_Z, rotation);
                        input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11]));
                }
                input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
@@ -1319,12 +1325,19 @@ static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom)
        unsigned char *data = wacom->data;
 
        int buttons = (data[282] << 1) | ((data[281] >> 6) & 0x01);
-       int ring = data[285];
-       int prox = buttons | (ring & 0x80);
+       int ring = data[285] & 0x7F;
+       bool ringstatus = data[285] & 0x80;
+       bool prox = buttons || ringstatus;
+
+       /* Fix touchring data: userspace expects 0 at left and increasing clockwise */
+       ring = 71 - ring;
+       ring += 3*72/16;
+       if (ring > 71)
+               ring -= 72;
 
        wacom_report_numbered_buttons(pad_input, 9, buttons);
 
-       input_report_abs(pad_input, ABS_WHEEL, (ring & 0x80) ? (ring & 0x7f) : 0);
+       input_report_abs(pad_input, ABS_WHEEL, ringstatus ? ring : 0);
 
        input_report_key(pad_input, wacom->tool[1], prox ? 1 : 0);
        input_report_abs(pad_input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
@@ -1616,6 +1629,20 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
        return 0;
 }
 
+static int wacom_offset_rotation(struct input_dev *input, struct hid_usage *usage,
+                                int value, int num, int denom)
+{
+       struct input_absinfo *abs = &input->absinfo[usage->code];
+       int range = (abs->maximum - abs->minimum + 1);
+
+       value += num*range/denom;
+       if (value > abs->maximum)
+               value -= range;
+       else if (value < abs->minimum)
+               value += range;
+       return value;
+}
+
 int wacom_equivalent_usage(int usage)
 {
        if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMDIGITIZER) {
@@ -1898,6 +1925,7 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
        unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
        int i;
        bool is_touch_on = value;
+       bool do_report = false;
 
        /*
         * Avoid reporting this event and setting inrange_state if this usage
@@ -1912,6 +1940,29 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
        }
 
        switch (equivalent_usage) {
+       case WACOM_HID_WD_TOUCHRING:
+               /*
+                * Userspace expects touchrings to increase in value with
+                * clockwise gestures and have their zero point at the
+                * tablet's left. HID events "should" be clockwise-
+                * increasing and zero at top, though the MobileStudio
+                * Pro and 2nd-gen Intuos Pro don't do this...
+                */
+               if (hdev->vendor == 0x56a &&
+                   (hdev->product == 0x34d || hdev->product == 0x34e ||  /* MobileStudio Pro */
+                    hdev->product == 0x357 || hdev->product == 0x358)) { /* Intuos Pro 2 */
+                       value = (field->logical_maximum - value);
+
+                       if (hdev->product == 0x357 || hdev->product == 0x358)
+                               value = wacom_offset_rotation(input, usage, value, 3, 16);
+                       else if (hdev->product == 0x34d || hdev->product == 0x34e)
+                               value = wacom_offset_rotation(input, usage, value, 1, 2);
+               }
+               else {
+                       value = wacom_offset_rotation(input, usage, value, 1, 4);
+               }
+               do_report = true;
+               break;
        case WACOM_HID_WD_TOUCHRINGSTATUS:
                if (!value)
                        input_event(input, usage->type, usage->code, 0);
@@ -1945,10 +1996,14 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
                                         value, i);
                 /* fall through*/
        default:
+               do_report = true;
+               break;
+       }
+
+       if (do_report) {
                input_event(input, usage->type, usage->code, value);
                if (value)
                        wacom_wac->hid_data.pad_input_event_flag = true;
-               break;
        }
 }
 
@@ -2086,22 +2141,34 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
                wacom_wac->hid_data.tipswitch |= value;
                return;
        case HID_DG_TOOLSERIALNUMBER:
-               wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL);
-               wacom_wac->serial[0] |= (__u32)value;
+               if (value) {
+                       wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL);
+                       wacom_wac->serial[0] |= (__u32)value;
+               }
                return;
+       case HID_DG_TWIST:
+               /*
+                * Userspace expects pen twist to have its zero point when
+                * the buttons/finger is on the tablet's left. HID values
+                * are zero when buttons are toward the top.
+                */
+               value = wacom_offset_rotation(input, usage, value, 1, 4);
+               break;
        case WACOM_HID_WD_SENSE:
                wacom_wac->hid_data.sense_state = value;
                return;
        case WACOM_HID_WD_SERIALHI:
-               wacom_wac->serial[0] = (wacom_wac->serial[0] & 0xFFFFFFFF);
-               wacom_wac->serial[0] |= ((__u64)value) << 32;
-               /*
-                * Non-USI EMR devices may contain additional tool type
-                * information here. See WACOM_HID_WD_TOOLTYPE case for
-                * more details.
-                */
-               if (value >> 20 == 1) {
-                       wacom_wac->id[0] |= value & 0xFFFFF;
+               if (value) {
+                       wacom_wac->serial[0] = (wacom_wac->serial[0] & 0xFFFFFFFF);
+                       wacom_wac->serial[0] |= ((__u64)value) << 32;
+                       /*
+                        * Non-USI EMR devices may contain additional tool type
+                        * information here. See WACOM_HID_WD_TOOLTYPE case for
+                        * more details.
+                        */
+                       if (value >> 20 == 1) {
+                               wacom_wac->id[0] |= value & 0xFFFFF;
+                       }
                }
                return;
        case WACOM_HID_WD_TOOLTYPE:
@@ -2205,7 +2272,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
                input_report_key(input, wacom_wac->tool[0], prox);
                if (wacom_wac->serial[0]) {
                        input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]);
-                       input_report_abs(input, ABS_MISC, id);
+                       input_report_abs(input, ABS_MISC, prox ? id : 0);
                }
 
                wacom_wac->hid_data.tipswitch = false;
@@ -2216,6 +2283,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
        if (!prox) {
                wacom_wac->tool[0] = 0;
                wacom_wac->id[0] = 0;
+               wacom_wac->serial[0] = 0;
        }
 }