Merge branches 'for-5.7/upstream-fixes', 'for-5.8/apple', 'for-5.8/asus', 'for-5...
authorJiri Kosina <jkosina@suse.cz>
Wed, 3 Jun 2020 20:23:52 +0000 (22:23 +0200)
committerJiri Kosina <jkosina@suse.cz>
Wed, 3 Jun 2020 20:23:52 +0000 (22:23 +0200)
drivers/hid/Kconfig
drivers/hid/hid-apple.c
drivers/hid/hid-asus.c
drivers/hid/hid-ids.h
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-mcp2221.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-quirks.c
drivers/hid/hid-sony.c
drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c

index 34f0737..443c5cb 100644 (file)
@@ -42,7 +42,7 @@ config HIDRAW
        ---help---
        Say Y here if you want to support HID devices (from the USB
        specification standpoint) that aren't strictly user interface
-       devices, like monitor controls and Uninterruptable Power Supplies.
+       devices, like monitor controls and Uninterruptible Power Supplies.
 
        This module supports these devices separately using a separate
        event interface on /dev/hidraw.
@@ -149,6 +149,7 @@ config HID_APPLEIR
 
 config HID_ASUS
        tristate "Asus"
+       depends on USB_HID
        depends on LEDS_CLASS
        depends on ASUS_WMI || ASUS_WMI=n
        select POWER_SUPPLY
@@ -538,14 +539,14 @@ config HID_LOGITECH
        Support for Logitech devices that are not fully compliant with HID standard.
 
 config HID_LOGITECH_DJ
-       tristate "Logitech Unifying receivers full support"
+       tristate "Logitech receivers full support"
        depends on USB_HID
        depends on HIDRAW
        depends on HID_LOGITECH
        select HID_LOGITECH_HIDPP
        ---help---
-       Say Y if you want support for Logitech Unifying receivers and devices.
-       Unifying receivers are capable of pairing up to 6 Logitech compliant
+       Say Y if you want support for Logitech receivers and devices.
+       Logitech receivers are capable of pairing multiple Logitech compliant
        devices to the same receiver. Without this driver it will be handled by
        generic USB_HID driver and all incoming events will be multiplexed
        into a single mouse and a single keyboard device.
@@ -1140,7 +1141,7 @@ config HID_SENSOR_CUSTOM_SENSOR
          to decide how to interpret these special sensor ids and process in
          the user space. Currently some manufacturers are using these ids for
          sensor calibration and debugging other sensors. Manufacturers
-         should't use these special custom sensor ids to export any of the
+         shouldn't use these special custom sensor ids to export any of the
          standard sensors.
          Select this config option for custom/generic sensor support.
 
index d732d1d..359bdfb 100644 (file)
@@ -51,6 +51,12 @@ MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\")
                "(For people who want to keep Windows PC keyboard muscle memory. "
                "[0] = as-is, Mac layout. 1 = swapped, Windows layout.)");
 
+static unsigned int swap_fn_leftctrl;
+module_param(swap_fn_leftctrl, uint, 0644);
+MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. "
+               "(For people who want to keep PC keyboard muscle memory. "
+               "[0] = as-is, Mac layout, 1 = swapped, PC layout)");
+
 struct apple_sc {
        unsigned long quirks;
        unsigned int fn_on;
@@ -162,6 +168,11 @@ static const struct apple_key_translation swapped_option_cmd_keys[] = {
        { }
 };
 
+static const struct apple_key_translation swapped_fn_leftctrl_keys[] = {
+       { KEY_FN, KEY_LEFTCTRL },
+       { }
+};
+
 static const struct apple_key_translation *apple_find_translation(
                const struct apple_key_translation *table, u16 from)
 {
@@ -183,9 +194,11 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
        bool do_translate;
        u16 code = 0;
 
-       if (usage->code == KEY_FN) {
+       u16 fn_keycode = (swap_fn_leftctrl) ? (KEY_LEFTCTRL) : (KEY_FN);
+
+       if (usage->code == fn_keycode) {
                asc->fn_on = !!value;
-               input_event(input, usage->type, usage->code, value);
+               input_event(input, usage->type, KEY_FN, value);
                return 1;
        }
 
@@ -270,6 +283,14 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
                }
        }
 
+       if (swap_fn_leftctrl) {
+               trans = apple_find_translation(swapped_fn_leftctrl_keys, usage->code);
+               if (trans) {
+                       input_event(input, usage->type, trans->to, value);
+                       return 1;
+               }
+       }
+
        return 0;
 }
 
@@ -333,6 +354,11 @@ static void apple_setup_input(struct input_dev *input)
 
        for (trans = apple_iso_keyboard; trans->from; trans++)
                set_bit(trans->to, input->keybit);
+
+       if (swap_fn_leftctrl) {
+               for (trans = swapped_fn_leftctrl_keys; trans->from; trans++)
+                       set_bit(trans->to, input->keybit);
+       }
 }
 
 static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
index e6e4c84..c183caf 100644 (file)
@@ -40,7 +40,9 @@ MODULE_AUTHOR("Frederik Wenigwieser <frederik.wenigwieser@gmail.com>");
 MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
 
 #define T100_TPAD_INTF 2
+#define MEDION_E1239T_TPAD_INTF 1
 
+#define E1239T_TP_TOGGLE_REPORT_ID 0x05
 #define T100CHI_MOUSE_REPORT_ID 0x06
 #define FEATURE_REPORT_ID 0x0d
 #define INPUT_REPORT_ID 0x5d
@@ -77,6 +79,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
 #define QUIRK_G752_KEYBOARD            BIT(8)
 #define QUIRK_T101HA_DOCK              BIT(9)
 #define QUIRK_T90CHI                   BIT(10)
+#define QUIRK_MEDION_E1239T            BIT(11)
 
 #define I2C_KEYBOARD_QUIRKS                    (QUIRK_FIX_NOTEBOOK_REPORT | \
                                                 QUIRK_NO_INIT_REPORTS | \
@@ -102,12 +105,14 @@ struct asus_touchpad_info {
        int res_y;
        int contact_size;
        int max_contacts;
+       int report_size;
 };
 
 struct asus_drvdata {
        unsigned long quirks;
        struct hid_device *hdev;
        struct input_dev *input;
+       struct input_dev *tp_kbd_input;
        struct asus_kbd_leds *kbd_backlight;
        const struct asus_touchpad_info *tp;
        bool enable_backlight;
@@ -126,6 +131,7 @@ static const struct asus_touchpad_info asus_i2c_tp = {
        .max_y = 1758,
        .contact_size = 5,
        .max_contacts = 5,
+       .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */,
 };
 
 static const struct asus_touchpad_info asus_t100ta_tp = {
@@ -135,6 +141,7 @@ static const struct asus_touchpad_info asus_t100ta_tp = {
        .res_y = 27, /* units/mm */
        .contact_size = 5,
        .max_contacts = 5,
+       .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */,
 };
 
 static const struct asus_touchpad_info asus_t100ha_tp = {
@@ -144,6 +151,7 @@ static const struct asus_touchpad_info asus_t100ha_tp = {
        .res_y = 29, /* units/mm */
        .contact_size = 5,
        .max_contacts = 5,
+       .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */,
 };
 
 static const struct asus_touchpad_info asus_t200ta_tp = {
@@ -153,6 +161,7 @@ static const struct asus_touchpad_info asus_t200ta_tp = {
        .res_y = 28, /* units/mm */
        .contact_size = 5,
        .max_contacts = 5,
+       .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */,
 };
 
 static const struct asus_touchpad_info asus_t100chi_tp = {
@@ -162,6 +171,17 @@ static const struct asus_touchpad_info asus_t100chi_tp = {
        .res_y = 29, /* units/mm */
        .contact_size = 3,
        .max_contacts = 4,
+       .report_size = 15 /* 2 byte header + 3 * 4 + 1 byte footer */,
+};
+
+static const struct asus_touchpad_info medion_e1239t_tp = {
+       .max_x = 2640,
+       .max_y = 1380,
+       .res_x = 29, /* units/mm */
+       .res_y = 28, /* units/mm */
+       .contact_size = 5,
+       .max_contacts = 5,
+       .report_size = 32 /* 2 byte header + 5 * 5 + 5 byte footer */,
 };
 
 static void asus_report_contact_down(struct asus_drvdata *drvdat,
@@ -229,7 +249,7 @@ static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size)
        int i, toolType = MT_TOOL_FINGER;
        u8 *contactData = data + 2;
 
-       if (size != 3 + drvdat->tp->contact_size * drvdat->tp->max_contacts)
+       if (size != drvdat->tp->report_size)
                return 0;
 
        for (i = 0; i < drvdat->tp->max_contacts; i++) {
@@ -257,6 +277,34 @@ static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size)
        return 1;
 }
 
+static int asus_e1239t_event(struct asus_drvdata *drvdat, u8 *data, int size)
+{
+       if (size != 3)
+               return 0;
+
+       /* Handle broken mute key which only sends press events */
+       if (!drvdat->tp &&
+           data[0] == 0x02 && data[1] == 0xe2 && data[2] == 0x00) {
+               input_report_key(drvdat->input, KEY_MUTE, 1);
+               input_sync(drvdat->input);
+               input_report_key(drvdat->input, KEY_MUTE, 0);
+               input_sync(drvdat->input);
+               return 1;
+       }
+
+       /* Handle custom touchpad toggle key which only sends press events */
+       if (drvdat->tp_kbd_input &&
+           data[0] == 0x05 && data[1] == 0x02 && data[2] == 0x28) {
+               input_report_key(drvdat->tp_kbd_input, KEY_F21, 1);
+               input_sync(drvdat->tp_kbd_input);
+               input_report_key(drvdat->tp_kbd_input, KEY_F21, 0);
+               input_sync(drvdat->tp_kbd_input);
+               return 1;
+       }
+
+       return 0;
+}
+
 static int asus_event(struct hid_device *hdev, struct hid_field *field,
                      struct hid_usage *usage, __s32 value)
 {
@@ -281,6 +329,9 @@ static int asus_raw_event(struct hid_device *hdev,
        if (drvdata->tp && data[0] == INPUT_REPORT_ID)
                return asus_report_input(drvdata, data, size);
 
+       if (drvdata->quirks & QUIRK_MEDION_E1239T)
+               return asus_e1239t_event(drvdata, data, size);
+
        return 0;
 }
 
@@ -615,6 +666,21 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
            hi->report->id != T100CHI_MOUSE_REPORT_ID)
                return 0;
 
+       /* Handle MULTI_INPUT on E1239T mouse/touchpad USB interface */
+       if (drvdata->tp && (drvdata->quirks & QUIRK_MEDION_E1239T)) {
+               switch (hi->report->id) {
+               case E1239T_TP_TOGGLE_REPORT_ID:
+                       input_set_capability(input, EV_KEY, KEY_F21);
+                       input->name = "Asus Touchpad Keys";
+                       drvdata->tp_kbd_input = input;
+                       return 0;
+               case INPUT_REPORT_ID:
+                       break; /* Touchpad report, handled below */
+               default:
+                       return 0; /* Ignore other reports */
+               }
+       }
+
        if (drvdata->tp) {
                int ret;
 
@@ -677,24 +743,16 @@ static int asus_input_mapping(struct hid_device *hdev,
         * This avoids a bunch of non-functional hid_input devices getting
         * created because of the T100CHI using HID_QUIRK_MULTI_INPUT.
         */
-       if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) {
-               if (field->application == (HID_UP_GENDESK | 0x0080) ||
-                   usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) ||
-                   usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) ||
-                   usage->hid == (HID_UP_GENDEVCTRLS | 0x0026))
-                       return -1;
-               /*
-                * We use the hid_input for the mouse report for the touchpad,
-                * keep the left button, to avoid the core removing it.
-                */
-               if (field->application == HID_GD_MOUSE &&
-                   usage->hid != (HID_UP_BUTTON | 1))
-                       return -1;
-       }
+       if ((drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) &&
+           (field->application == (HID_UP_GENDESK | 0x0080) ||
+            field->application == HID_GD_MOUSE ||
+            usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) ||
+            usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) ||
+            usage->hid == (HID_UP_GENDEVCTRLS | 0x0026)))
+               return -1;
 
        /* ASUS-specific keyboard hotkeys */
        if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) {
-               set_bit(EV_REP, hi->input->evbit);
                switch (usage->hid & HID_USAGE) {
                case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN);      break;
                case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP);                break;
@@ -737,11 +795,11 @@ static int asus_input_mapping(struct hid_device *hdev,
                if (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT)
                        drvdata->enable_backlight = true;
 
+               set_bit(EV_REP, hi->input->evbit);
                return 1;
        }
 
        if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) {
-               set_bit(EV_REP, hi->input->evbit);
                switch (usage->hid & HID_USAGE) {
                case 0xff01: asus_map_key_clear(BTN_1); break;
                case 0xff02: asus_map_key_clear(BTN_2); break;
@@ -764,6 +822,7 @@ static int asus_input_mapping(struct hid_device *hdev,
                        return 0;
                }
 
+               set_bit(EV_REP, hi->input->evbit);
                return 1;
        }
 
@@ -782,6 +841,16 @@ static int asus_input_mapping(struct hid_device *hdev,
                }
        }
 
+       /*
+        * The mute button is broken and only sends press events, we
+        * deal with this in our raw_event handler, so do not map it.
+        */
+       if ((drvdata->quirks & QUIRK_MEDION_E1239T) &&
+           usage->hid == (HID_UP_CONSUMER | 0xe2)) {
+               input_set_capability(hi->input, EV_KEY, KEY_MUTE);
+               return -1;
+       }
+
        return 0;
 }
 
@@ -849,7 +918,8 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (drvdata->quirks & QUIRK_IS_MULTITOUCH)
                drvdata->tp = &asus_i2c_tp;
 
-       if (drvdata->quirks & QUIRK_T100_KEYBOARD) {
+       if ((drvdata->quirks & QUIRK_T100_KEYBOARD) &&
+           hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
                struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 
                if (intf->altsetting->desc.bInterfaceNumber == T100_TPAD_INTF) {
@@ -877,6 +947,19 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
                drvdata->tp = &asus_t100chi_tp;
        }
 
+       if ((drvdata->quirks & QUIRK_MEDION_E1239T) &&
+           hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
+               struct usb_host_interface *alt =
+                       to_usb_interface(hdev->dev.parent)->altsetting;
+
+               if (alt->desc.bInterfaceNumber == MEDION_E1239T_TPAD_INTF) {
+                       /* For separate input-devs for tp and tp toggle key */
+                       hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+                       drvdata->quirks |= QUIRK_SKIP_INPUT_MAPPING;
+                       drvdata->tp = &medion_e1239t_tp;
+               }
+       }
+
        if (drvdata->quirks & QUIRK_NO_INIT_REPORTS)
                hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
 
@@ -1056,7 +1139,8 @@ static const struct hid_device_id asus_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
                USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD), QUIRK_T100CHI },
-
+       { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE_MEDION_E1239T),
+               QUIRK_MEDION_E1239T },
        { }
 };
 MODULE_DEVICE_TABLE(hid, asus_devices);
index 1c71a1a..874fc37 100644 (file)
 
 #define USB_VENDOR_ID_ALPS_JP          0x044E
 #define HID_DEVICE_ID_ALPS_U1_DUAL     0x120B
-#define HID_DEVICE_ID_ALPS_U1_DUAL_PTP 0x121F
-#define HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP    0x1220
 #define HID_DEVICE_ID_ALPS_U1          0x1215
 #define HID_DEVICE_ID_ALPS_U1_UNICORN_LEGACY         0x121E
 #define HID_DEVICE_ID_ALPS_T4_BTNLESS  0x120C
-#define HID_DEVICE_ID_ALPS_1222                0x1222
 
 #define USB_VENDOR_ID_AMI              0x046b
 #define USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE      0xff10
 
 #define USB_VENDOR_ID_CIDC             0x1677
 
-#define I2C_VENDOR_ID_CIRQUE           0x0488
-#define I2C_PRODUCT_ID_CIRQUE_121F     0x121F
-
 #define USB_VENDOR_ID_CJTOUCH          0x24b8
 #define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020
 #define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040
 #define I2C_DEVICE_ID_ITE_LENOVO_LEGION_Y720   0x837a
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA900       0x8396
 #define USB_DEVICE_ID_ITE8595          0x8595
+#define USB_DEVICE_ID_ITE_MEDION_E1239T        0xce50
 
 #define USB_VENDOR_ID_JABRA            0x0b0e
 #define USB_DEVICE_ID_JABRA_SPEAK_410  0x0412
 #define USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL       0x6049
 #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_DEVICE_ID_LENOVO_X1_TAB3   0x60b5
 #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D     0x608d
 
 #define USB_VENDOR_ID_LG               0x1fd2
 #define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882     0x8882
 #define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883     0x8883
 
+#define USB_VENDOR_ID_TRUST             0x145f
+#define USB_DEVICE_ID_TRUST_PANORA_TABLET   0x0212
+
 #define USB_VENDOR_ID_TURBOX           0x062a
 #define USB_DEVICE_ID_TURBOX_KEYBOARD  0x0201
 #define USB_DEVICE_ID_ASUS_MD_5110     0x5110
index ed9b1c1..48dff5d 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- *  HID driver for Logitech Unifying receivers
+ *  HID driver for Logitech receivers
  *
  *  Copyright (c) 2011 Logitech
  */
@@ -701,7 +701,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
                        type_str, dj_hiddev->product);
        } else {
                snprintf(dj_hiddev->name, sizeof(dj_hiddev->name),
-                       "Logitech Unifying Device. Wireless PID:%04x",
+                       "Logitech Wireless Device PID:%04x",
                        dj_hiddev->product);
        }
 
index 094f4f1..1e1cf8e 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- *  HIDPP protocol for Logitech Unifying receivers
+ *  HIDPP protocol for Logitech receivers
  *
  *  Copyright (c) 2011 Logitech (c)
  *  Copyright (c) 2012-2013 Google (c)
index d958475..e1b93ce 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/hid.h>
 #include <linux/hidraw.h>
 #include <linux/i2c.h>
+#include <linux/gpio/driver.h>
 #include "hid-ids.h"
 
 /* Commands codes in a raw output report */
@@ -27,6 +28,8 @@ enum {
        MCP2221_I2C_PARAM_OR_STATUS     = 0x10,
        MCP2221_I2C_SET_SPEED = 0x20,
        MCP2221_I2C_CANCEL = 0x10,
+       MCP2221_GPIO_SET = 0x50,
+       MCP2221_GPIO_GET = 0x51,
 };
 
 /* Response codes in a raw input report */
@@ -42,6 +45,8 @@ enum {
        MCP2221_I2C_WRADDRL_SEND = 0x21,
        MCP2221_I2C_ADDR_NACK = 0x25,
        MCP2221_I2C_READ_COMPL = 0x55,
+       MCP2221_ALT_F_NOT_GPIOV = 0xEE,
+       MCP2221_ALT_F_NOT_GPIOD = 0xEF,
 };
 
 /*
@@ -59,6 +64,9 @@ struct mcp2221 {
        int rxbuf_idx;
        int status;
        u8 cur_i2c_clk_div;
+       struct gpio_chip *gc;
+       u8 gp_idx;
+       u8 gpio_dir;
 };
 
 /*
@@ -526,6 +534,110 @@ static const struct i2c_algorithm mcp_i2c_algo = {
        .functionality = mcp_i2c_func,
 };
 
+static int mcp_gpio_get(struct gpio_chip *gc,
+                               unsigned int offset)
+{
+       int ret;
+       struct mcp2221 *mcp = gpiochip_get_data(gc);
+
+       mcp->txbuf[0] = MCP2221_GPIO_GET;
+
+       mcp->gp_idx = (offset + 1) * 2;
+
+       mutex_lock(&mcp->lock);
+       ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
+       mutex_unlock(&mcp->lock);
+
+       return ret;
+}
+
+static void mcp_gpio_set(struct gpio_chip *gc,
+                               unsigned int offset, int value)
+{
+       struct mcp2221 *mcp = gpiochip_get_data(gc);
+
+       memset(mcp->txbuf, 0, 18);
+       mcp->txbuf[0] = MCP2221_GPIO_SET;
+
+       mcp->gp_idx = ((offset + 1) * 4) - 1;
+
+       mcp->txbuf[mcp->gp_idx - 1] = 1;
+       mcp->txbuf[mcp->gp_idx] = !!value;
+
+       mutex_lock(&mcp->lock);
+       mcp_send_data_req_status(mcp, mcp->txbuf, 18);
+       mutex_unlock(&mcp->lock);
+}
+
+static int mcp_gpio_dir_set(struct mcp2221 *mcp,
+                               unsigned int offset, u8 val)
+{
+       memset(mcp->txbuf, 0, 18);
+       mcp->txbuf[0] = MCP2221_GPIO_SET;
+
+       mcp->gp_idx = (offset + 1) * 5;
+
+       mcp->txbuf[mcp->gp_idx - 1] = 1;
+       mcp->txbuf[mcp->gp_idx] = val;
+
+       return mcp_send_data_req_status(mcp, mcp->txbuf, 18);
+}
+
+static int mcp_gpio_direction_input(struct gpio_chip *gc,
+                               unsigned int offset)
+{
+       int ret;
+       struct mcp2221 *mcp = gpiochip_get_data(gc);
+
+       mutex_lock(&mcp->lock);
+       ret = mcp_gpio_dir_set(mcp, offset, 0);
+       mutex_unlock(&mcp->lock);
+
+       return ret;
+}
+
+static int mcp_gpio_direction_output(struct gpio_chip *gc,
+                               unsigned int offset, int value)
+{
+       int ret;
+       struct mcp2221 *mcp = gpiochip_get_data(gc);
+
+       mutex_lock(&mcp->lock);
+       ret = mcp_gpio_dir_set(mcp, offset, 1);
+       mutex_unlock(&mcp->lock);
+
+       /* Can't configure as output, bailout early */
+       if (ret)
+               return ret;
+
+       mcp_gpio_set(gc, offset, value);
+
+       return 0;
+}
+
+static int mcp_gpio_get_direction(struct gpio_chip *gc,
+                               unsigned int offset)
+{
+       int ret;
+       struct mcp2221 *mcp = gpiochip_get_data(gc);
+
+       mcp->txbuf[0] = MCP2221_GPIO_GET;
+
+       mcp->gp_idx = (offset + 1) * 2;
+
+       mutex_lock(&mcp->lock);
+       ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
+       mutex_unlock(&mcp->lock);
+
+       if (ret)
+               return ret;
+
+       if (mcp->gpio_dir)
+               return GPIO_LINE_DIRECTION_IN;
+
+       return GPIO_LINE_DIRECTION_OUT;
+}
+
 /* Gives current state of i2c engine inside mcp2221 */
 static int mcp_get_i2c_eng_state(struct mcp2221 *mcp,
                                u8 *data, u8 idx)
@@ -638,6 +750,39 @@ static int mcp2221_raw_event(struct hid_device *hdev,
                complete(&mcp->wait_in_report);
                break;
 
+       case MCP2221_GPIO_GET:
+               switch (data[1]) {
+               case MCP2221_SUCCESS:
+                       if ((data[mcp->gp_idx] == MCP2221_ALT_F_NOT_GPIOV) ||
+                               (data[mcp->gp_idx + 1] == MCP2221_ALT_F_NOT_GPIOD)) {
+                               mcp->status = -ENOENT;
+                       } else {
+                               mcp->status = !!data[mcp->gp_idx];
+                               mcp->gpio_dir = !!data[mcp->gp_idx + 1];
+                       }
+                       break;
+               default:
+                       mcp->status = -EAGAIN;
+               }
+               complete(&mcp->wait_in_report);
+               break;
+
+       case MCP2221_GPIO_SET:
+               switch (data[1]) {
+               case MCP2221_SUCCESS:
+                       if ((data[mcp->gp_idx] == MCP2221_ALT_F_NOT_GPIOV) ||
+                               (data[mcp->gp_idx - 1] == MCP2221_ALT_F_NOT_GPIOV)) {
+                               mcp->status = -ENOENT;
+                       } else {
+                               mcp->status = 0;
+                       }
+                       break;
+               default:
+                       mcp->status = -EAGAIN;
+               }
+               complete(&mcp->wait_in_report);
+               break;
+
        default:
                mcp->status = -EIO;
                complete(&mcp->wait_in_report);
@@ -702,8 +847,32 @@ static int mcp2221_probe(struct hid_device *hdev,
        }
        i2c_set_adapdata(&mcp->adapter, mcp);
 
+       /* Setup GPIO chip */
+       mcp->gc = devm_kzalloc(&hdev->dev, sizeof(*mcp->gc), GFP_KERNEL);
+       if (!mcp->gc) {
+               ret = -ENOMEM;
+               goto err_gc;
+       }
+
+       mcp->gc->label = "mcp2221_gpio";
+       mcp->gc->direction_input = mcp_gpio_direction_input;
+       mcp->gc->direction_output = mcp_gpio_direction_output;
+       mcp->gc->get_direction = mcp_gpio_get_direction;
+       mcp->gc->set = mcp_gpio_set;
+       mcp->gc->get = mcp_gpio_get;
+       mcp->gc->ngpio = 4;
+       mcp->gc->base = -1;
+       mcp->gc->can_sleep = 1;
+       mcp->gc->parent = &hdev->dev;
+
+       ret = devm_gpiochip_add_data(&hdev->dev, mcp->gc, mcp);
+       if (ret)
+               goto err_gc;
+
        return 0;
 
+err_gc:
+       i2c_del_adapter(&mcp->adapter);
 err_i2c:
        hid_hw_close(mcp->hdev);
 err_hstop:
index 03c720b..35c8c17 100644 (file)
@@ -69,6 +69,7 @@ MODULE_LICENSE("GPL");
 #define MT_QUIRK_ASUS_CUSTOM_UP                BIT(17)
 #define MT_QUIRK_WIN8_PTP_BUTTONS      BIT(18)
 #define MT_QUIRK_SEPARATE_APP_REPORT   BIT(19)
+#define MT_QUIRK_FORCE_MULTI_INPUT     BIT(20)
 
 #define MT_INPUTMODE_TOUCHSCREEN       0x02
 #define MT_INPUTMODE_TOUCHPAD          0x03
@@ -188,7 +189,8 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
 /* reserved                                    0x0011 */
 #define MT_CLS_WIN_8                           0x0012
 #define MT_CLS_EXPORT_ALL_INPUTS               0x0013
-#define MT_CLS_WIN_8_DUAL                      0x0014
+/* reserved                                    0x0014 */
+#define MT_CLS_WIN_8_FORCE_MULTI_INPUT         0x0015
 
 /* vendor specific classes */
 #define MT_CLS_3M                              0x0101
@@ -272,12 +274,14 @@ static const struct mt_class mt_classes[] = {
                .quirks = MT_QUIRK_ALWAYS_VALID |
                        MT_QUIRK_CONTACT_CNT_ACCURATE,
                .export_all_inputs = true },
-       { .name = MT_CLS_WIN_8_DUAL,
+       { .name = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
                .quirks = MT_QUIRK_ALWAYS_VALID |
                        MT_QUIRK_IGNORE_DUPLICATES |
                        MT_QUIRK_HOVERING |
                        MT_QUIRK_CONTACT_CNT_ACCURATE |
-                       MT_QUIRK_WIN8_PTP_BUTTONS,
+                       MT_QUIRK_STICKY_FINGERS |
+                       MT_QUIRK_WIN8_PTP_BUTTONS |
+                       MT_QUIRK_FORCE_MULTI_INPUT,
                .export_all_inputs = true },
 
        /*
@@ -754,8 +758,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        MT_STORE_FIELD(inrange_state);
                        return 1;
                case HID_DG_CONFIDENCE:
-                       if ((cls->name == MT_CLS_WIN_8 ||
-                               cls->name == MT_CLS_WIN_8_DUAL) &&
+                       if (cls->name == MT_CLS_WIN_8 &&
                                (field->application == HID_DG_TOUCHPAD ||
                                 field->application == HID_DG_TOUCHSCREEN))
                                app->quirks |= MT_QUIRK_CONFIDENCE;
@@ -1714,6 +1717,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (id->group != HID_GROUP_MULTITOUCH_WIN_8)
                hdev->quirks |= HID_QUIRK_MULTI_INPUT;
 
+       if (mtclass->quirks & MT_QUIRK_FORCE_MULTI_INPUT) {
+               hdev->quirks &= ~HID_QUIRK_INPUT_PER_APP;
+               hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+       }
+
        timer_setup(&td->release_timer, mt_expired_timeout, 0);
 
        ret = hid_parse(hdev);
@@ -1786,32 +1794,6 @@ static const struct hid_device_id mt_devices[] = {
                MT_USB_DEVICE(USB_VENDOR_ID_3M,
                        USB_DEVICE_ID_3M3266) },
 
-       /* Alps devices */
-       { .driver_data = MT_CLS_WIN_8_DUAL,
-               HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
-                       USB_VENDOR_ID_ALPS_JP,
-                       HID_DEVICE_ID_ALPS_U1_DUAL_PTP) },
-       { .driver_data = MT_CLS_WIN_8_DUAL,
-               HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
-                       USB_VENDOR_ID_ALPS_JP,
-                       HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) },
-       { .driver_data = MT_CLS_WIN_8_DUAL,
-               HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
-                       USB_VENDOR_ID_ALPS_JP,
-                       HID_DEVICE_ID_ALPS_1222) },
-
-       /* 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) },
-
-       /* Lenovo X1 TAB Gen 3 */
-       { .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_TAB3) },
-
        /* Anton devices */
        { .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
                MT_USB_DEVICE(USB_VENDOR_ID_ANTON,
@@ -1846,12 +1828,6 @@ static const struct hid_device_id mt_devices[] = {
                MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
                        USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
 
-       /* Cirque devices */
-       { .driver_data = MT_CLS_WIN_8_DUAL,
-               HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
-                       I2C_VENDOR_ID_CIRQUE,
-                       I2C_PRODUCT_ID_CIRQUE_121F) },
-
        /* CJTouch panels */
        { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH,
@@ -1926,6 +1902,11 @@ static const struct hid_device_id mt_devices[] = {
                MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) },
 
+       /* Elan devices */
+       { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
+               HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+                       USB_VENDOR_ID_ELAN, 0x313a) },
+
        /* Elitegroup panel */
        { .driver_data = MT_CLS_SERIAL,
                MT_USB_DEVICE(USB_VENDOR_ID_ELITEGROUP,
@@ -2056,6 +2037,11 @@ static const struct hid_device_id mt_devices[] = {
                MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
                        USB_DEVICE_ID_MTP_STM)},
 
+       /* Synaptics devices */
+       { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
+               HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+                       USB_VENDOR_ID_SYNAPTICS, 0xce08) },
+
        /* TopSeed panels */
        { .driver_data = MT_CLS_TOPSEED,
                MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,
index e4cb543..ca8b5c2 100644 (file)
@@ -168,6 +168,7 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882), HID_QUIRK_NOGET },
        { HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883), HID_QUIRK_NOGET },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TRUST, USB_DEVICE_ID_TRUST_PANORA_TABLET), HID_QUIRK_MULTI_INPUT | HID_QUIRK_HIDINPUT_FORCE },
        { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD), HID_QUIRK_NOGET },
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60), HID_QUIRK_MULTI_INPUT },
index 4c6ed6e..2f073f5 100644 (file)
@@ -867,6 +867,23 @@ static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc,
        if (sc->quirks & PS3REMOTE)
                return ps3remote_fixup(hdev, rdesc, rsize);
 
+       /*
+        * Some knock-off USB dongles incorrectly report their button count
+        * as 13 instead of 16 causing three non-functional buttons.
+        */
+       if ((sc->quirks & SIXAXIS_CONTROLLER_USB) && *rsize >= 45 &&
+               /* Report Count (13) */
+               rdesc[23] == 0x95 && rdesc[24] == 0x0D &&
+               /* Usage Maximum (13) */
+               rdesc[37] == 0x29 && rdesc[38] == 0x0D &&
+               /* Report Count (3) */
+               rdesc[43] == 0x95 && rdesc[44] == 0x03) {
+               hid_info(hdev, "Fixing up USB dongle report descriptor\n");
+               rdesc[24] = 0x10;
+               rdesc[38] = 0x10;
+               rdesc[44] = 0x00;
+       }
+
        return rdesc;
 }
 
index a66f080..ec142bc 100644 (file)
@@ -389,6 +389,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
                },
                .driver_data = (void *)&sipodev_desc
        },
+       {
+               .ident = "Schneider SCL142ALM",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SCHNEIDER"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SCL142ALM"),
+               },
+               .driver_data = (void *)&sipodev_desc
+       },
        { }     /* Terminate list */
 };