Merge branches 'for-3.17/upstream', 'for-3.17/cp2112', 'for-3.17/huion', 'for-3.17...
authorJiri Kosina <jkosina@suse.cz>
Wed, 6 Aug 2014 09:09:53 +0000 (11:09 +0200)
committerJiri Kosina <jkosina@suse.cz>
Wed, 6 Aug 2014 09:09:53 +0000 (11:09 +0200)
13 files changed:
drivers/hid/Kconfig
drivers/hid/hid-core.c
drivers/hid/hid-cp2112.c
drivers/hid/hid-huion.c
drivers/hid/hid-hyperv.c
drivers/hid/hid-ids.h
drivers/hid/hid-picolcd_debugfs.c
drivers/hid/hid-rmi.c
drivers/hid/hid-roccat-lua.c
drivers/hid/hid-sony.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-quirks.c

index 21cce19..e02cf59 100644 (file)
@@ -787,7 +787,7 @@ config HID_XINMO
        depends on HID
        ---help---
        Support for Xin-Mo devices that are not fully compliant with the HID
-       standard. Currently only supports the Xin-Mo Dual Arcade. Say Y here
+       standard. Currently only supports the Xin-Mo Dual Arcade. Say Y here
        if you have a Xin-Mo Dual Arcade controller.
 
 config HID_ZEROPLUS
index 81b3bb6..6c813c6 100644 (file)
@@ -783,7 +783,9 @@ static int hid_scan_report(struct hid_device *hid)
        * Vendor specific handlings
        */
        if ((hid->vendor == USB_VENDOR_ID_SYNAPTICS) &&
-           (hid->group == HID_GROUP_GENERIC))
+           (hid->group == HID_GROUP_GENERIC) &&
+           /* only bind to the mouse interface of composite USB devices */
+           (hid->bus != BUS_USB || hid->type == HID_TYPE_USBMOUSE))
                /* hid-rmi should take care of them, not hid-generic */
                hid->group = HID_GROUP_RMI;
 
@@ -1782,7 +1784,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A070) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
        { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
@@ -2268,6 +2270,7 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) },
        { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_410) },
        { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_510) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_GN9350E) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
index 56be85a..a822db5 100644 (file)
@@ -240,8 +240,6 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip,
        u8 buf[5];
        int ret;
 
-       cp2112_gpio_set(chip, offset, value);
-
        ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
                                       sizeof(buf), HID_FEATURE_REPORT,
                                       HID_REQ_GET_REPORT);
@@ -260,6 +258,12 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip,
                return ret;
        }
 
+       /*
+        * Set gpio value when output direction is already set,
+        * as specified in AN495, Rev. 0.2, cpt. 4.4
+        */
+       cp2112_gpio_set(chip, offset, value);
+
        return 0;
 }
 
@@ -425,6 +429,105 @@ static int cp2112_write_req(void *buf, u8 slave_address, u8 command, u8 *data,
        return data_length + 4;
 }
 
+static int cp2112_i2c_write_req(void *buf, u8 slave_address, u8 *data,
+                               u8 data_length)
+{
+       struct cp2112_write_req_report *report = buf;
+
+       if (data_length > sizeof(report->data))
+               return -EINVAL;
+
+       report->report = CP2112_DATA_WRITE_REQUEST;
+       report->slave_address = slave_address << 1;
+       report->length = data_length;
+       memcpy(report->data, data, data_length);
+       return data_length + 3;
+}
+
+static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+                          int num)
+{
+       struct cp2112_device *dev = (struct cp2112_device *)adap->algo_data;
+       struct hid_device *hdev = dev->hdev;
+       u8 buf[64];
+       ssize_t count;
+       unsigned int retries;
+       int ret;
+
+       hid_dbg(hdev, "I2C %d messages\n", num);
+
+       if (num != 1) {
+               hid_err(hdev,
+                       "Multi-message I2C transactions not supported\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (msgs->flags & I2C_M_RD)
+               count = cp2112_read_req(buf, msgs->addr, msgs->len);
+       else
+               count = cp2112_i2c_write_req(buf, msgs->addr, msgs->buf,
+                                            msgs->len);
+
+       if (count < 0)
+               return count;
+
+       ret = hid_hw_power(hdev, PM_HINT_FULLON);
+       if (ret < 0) {
+               hid_err(hdev, "power management error: %d\n", ret);
+               return ret;
+       }
+
+       ret = cp2112_hid_output(hdev, buf, count, HID_OUTPUT_REPORT);
+       if (ret < 0) {
+               hid_warn(hdev, "Error starting transaction: %d\n", ret);
+               goto power_normal;
+       }
+
+       for (retries = 0; retries < XFER_STATUS_RETRIES; ++retries) {
+               ret = cp2112_xfer_status(dev);
+               if (-EBUSY == ret)
+                       continue;
+               if (ret < 0)
+                       goto power_normal;
+               break;
+       }
+
+       if (XFER_STATUS_RETRIES <= retries) {
+               hid_warn(hdev, "Transfer timed out, cancelling.\n");
+               buf[0] = CP2112_CANCEL_TRANSFER;
+               buf[1] = 0x01;
+
+               ret = cp2112_hid_output(hdev, buf, 2, HID_OUTPUT_REPORT);
+               if (ret < 0)
+                       hid_warn(hdev, "Error cancelling transaction: %d\n",
+                                ret);
+
+               ret = -ETIMEDOUT;
+               goto power_normal;
+       }
+
+       if (!(msgs->flags & I2C_M_RD))
+               goto finish;
+
+       ret = cp2112_read(dev, msgs->buf, msgs->len);
+       if (ret < 0)
+               goto power_normal;
+       if (ret != msgs->len) {
+               hid_warn(hdev, "short read: %d < %d\n", ret, msgs->len);
+               ret = -EIO;
+               goto power_normal;
+       }
+
+finish:
+       /* return the number of transferred messages */
+       ret = 1;
+
+power_normal:
+       hid_hw_power(hdev, PM_HINT_NORMAL);
+       hid_dbg(hdev, "I2C transfer finished: %d\n", ret);
+       return ret;
+}
+
 static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
                       unsigned short flags, char read_write, u8 command,
                       int size, union i2c_smbus_data *data)
@@ -591,7 +694,8 @@ power_normal:
 
 static u32 cp2112_functionality(struct i2c_adapter *adap)
 {
-       return I2C_FUNC_SMBUS_BYTE |
+       return I2C_FUNC_I2C |
+               I2C_FUNC_SMBUS_BYTE |
                I2C_FUNC_SMBUS_BYTE_DATA |
                I2C_FUNC_SMBUS_WORD_DATA |
                I2C_FUNC_SMBUS_BLOCK_DATA |
@@ -601,6 +705,7 @@ static u32 cp2112_functionality(struct i2c_adapter *adap)
 }
 
 static const struct i2c_algorithm smbus_algorithm = {
+       .master_xfer    = cp2112_i2c_xfer,
        .smbus_xfer     = cp2112_xfer,
        .functionality  = cp2112_functionality,
 };
index cbf4da4..60f44cd 100644 (file)
@@ -2,6 +2,7 @@
  *  HID driver for Huion devices not fully compliant with HID standard
  *
  *  Copyright (c) 2013 Martin Rusko
+ *  Copyright (c) 2014 Nikolai Kondrashov
  */
 
 /*
 #include <linux/hid.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <asm/unaligned.h>
 #include "usbhid/usbhid.h"
 
 #include "hid-ids.h"
 
-/* Original Huion 580 report descriptor size */
-#define HUION_580_RDESC_ORIG_SIZE      177
-
-/* Fixed Huion 580 report descriptor */
-static __u8 huion_580_rdesc_fixed[] = {
-       0x05, 0x0D,         /*  Usage Page (Digitizer),             */
-       0x09, 0x02,         /*  Usage (Pen),                        */
-       0xA1, 0x01,         /*  Collection (Application),           */
-       0x85, 0x07,         /*      Report ID (7),                  */
-       0x09, 0x20,         /*      Usage (Stylus),                 */
-       0xA0,               /*      Collection (Physical),          */
-       0x14,               /*          Logical Minimum (0),        */
-       0x25, 0x01,         /*          Logical Maximum (1),        */
-       0x75, 0x01,         /*          Report Size (1),            */
-       0x09, 0x42,         /*          Usage (Tip Switch),         */
-       0x09, 0x44,         /*          Usage (Barrel Switch),      */
-       0x09, 0x46,         /*          Usage (Tablet Pick),        */
-       0x95, 0x03,         /*          Report Count (3),           */
-       0x81, 0x02,         /*          Input (Variable),           */
-       0x95, 0x03,         /*          Report Count (3),           */
-       0x81, 0x03,         /*          Input (Constant, Variable), */
-       0x09, 0x32,         /*          Usage (In Range),           */
-       0x95, 0x01,         /*          Report Count (1),           */
-       0x81, 0x02,         /*          Input (Variable),           */
-       0x95, 0x01,         /*          Report Count (1),           */
-       0x81, 0x03,         /*          Input (Constant, Variable), */
-       0x75, 0x10,         /*          Report Size (16),           */
-       0x95, 0x01,         /*          Report Count (1),           */
-       0xA4,               /*          Push,                       */
-       0x05, 0x01,         /*          Usage Page (Desktop),       */
-       0x65, 0x13,         /*          Unit (Inch),                */
-       0x55, 0xFD,         /*          Unit Exponent (-3),         */
-       0x34,               /*          Physical Minimum (0),       */
-       0x09, 0x30,         /*          Usage (X),                  */
-       0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
-       0x26, 0x00, 0x7D,   /*          Logical Maximum (32000),    */
-       0x81, 0x02,         /*          Input (Variable),           */
-       0x09, 0x31,         /*          Usage (Y),                  */
-       0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */
-       0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
-       0x81, 0x02,         /*          Input (Variable),           */
-       0xB4,               /*          Pop,                        */
-       0x09, 0x30,         /*          Usage (Tip Pressure),       */
-       0x26, 0xFF, 0x07,   /*          Logical Maximum (2047),     */
-       0x81, 0x02,         /*          Input (Variable),           */
-       0xC0,               /*      End Collection,                 */
-       0xC0                /*  End Collection                      */
+/* Report descriptor template placeholder head */
+#define HUION_PH_HEAD  0xFE, 0xED, 0x1D
+
+/* Report descriptor template placeholder IDs */
+enum huion_ph_id {
+       HUION_PH_ID_X_LM,
+       HUION_PH_ID_X_PM,
+       HUION_PH_ID_Y_LM,
+       HUION_PH_ID_Y_PM,
+       HUION_PH_ID_PRESSURE_LM,
+       HUION_PH_ID_NUM
+};
+
+/* Report descriptor template placeholder */
+#define HUION_PH(_ID) HUION_PH_HEAD, HUION_PH_ID_##_ID
+
+/* Fixed report descriptor template */
+static const __u8 huion_tablet_rdesc_template[] = {
+       0x05, 0x0D,             /*  Usage Page (Digitizer),                 */
+       0x09, 0x02,             /*  Usage (Pen),                            */
+       0xA1, 0x01,             /*  Collection (Application),               */
+       0x85, 0x07,             /*      Report ID (7),                      */
+       0x09, 0x20,             /*      Usage (Stylus),                     */
+       0xA0,                   /*      Collection (Physical),              */
+       0x14,                   /*          Logical Minimum (0),            */
+       0x25, 0x01,             /*          Logical Maximum (1),            */
+       0x75, 0x01,             /*          Report Size (1),                */
+       0x09, 0x42,             /*          Usage (Tip Switch),             */
+       0x09, 0x44,             /*          Usage (Barrel Switch),          */
+       0x09, 0x46,             /*          Usage (Tablet Pick),            */
+       0x95, 0x03,             /*          Report Count (3),               */
+       0x81, 0x02,             /*          Input (Variable),               */
+       0x95, 0x03,             /*          Report Count (3),               */
+       0x81, 0x03,             /*          Input (Constant, Variable),     */
+       0x09, 0x32,             /*          Usage (In Range),               */
+       0x95, 0x01,             /*          Report Count (1),               */
+       0x81, 0x02,             /*          Input (Variable),               */
+       0x95, 0x01,             /*          Report Count (1),               */
+       0x81, 0x03,             /*          Input (Constant, Variable),     */
+       0x75, 0x10,             /*          Report Size (16),               */
+       0x95, 0x01,             /*          Report Count (1),               */
+       0xA4,                   /*          Push,                           */
+       0x05, 0x01,             /*          Usage Page (Desktop),           */
+       0x65, 0x13,             /*          Unit (Inch),                    */
+       0x55, 0xFD,             /*          Unit Exponent (-3),             */
+       0x34,                   /*          Physical Minimum (0),           */
+       0x09, 0x30,             /*          Usage (X),                      */
+       0x27, HUION_PH(X_LM),   /*          Logical Maximum (PLACEHOLDER),  */
+       0x47, HUION_PH(X_PM),   /*          Physical Maximum (PLACEHOLDER), */
+       0x81, 0x02,             /*          Input (Variable),               */
+       0x09, 0x31,             /*          Usage (Y),                      */
+       0x27, HUION_PH(Y_LM),   /*          Logical Maximum (PLACEHOLDER),  */
+       0x47, HUION_PH(Y_PM),   /*          Physical Maximum (PLACEHOLDER), */
+       0x81, 0x02,             /*          Input (Variable),               */
+       0xB4,                   /*          Pop,                            */
+       0x09, 0x30,             /*          Usage (Tip Pressure),           */
+       0x27,
+       HUION_PH(PRESSURE_LM),  /*          Logical Maximum (PLACEHOLDER),  */
+       0x81, 0x02,             /*          Input (Variable),               */
+       0xC0,                   /*      End Collection,                     */
+       0xC0                    /*  End Collection                          */
+};
+
+/* Driver data */
+struct huion_drvdata {
+       __u8 *rdesc;
+       unsigned int rsize;
 };
 
 static __u8 *huion_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
+       struct huion_drvdata *drvdata = hid_get_drvdata(hdev);
        switch (hdev->product) {
-       case USB_DEVICE_ID_HUION_580:
-               if (*rsize == HUION_580_RDESC_ORIG_SIZE) {
-                       rdesc = huion_580_rdesc_fixed;
-                       *rsize = sizeof(huion_580_rdesc_fixed);
+       case USB_DEVICE_ID_HUION_TABLET:
+               if (drvdata->rdesc != NULL) {
+                       rdesc = drvdata->rdesc;
+                       *rsize = drvdata->rsize;
                }
                break;
        }
@@ -83,82 +106,144 @@ static __u8 *huion_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 }
 
 /**
- * Enable fully-functional tablet mode by reading special string
- * descriptor.
+ * Enable fully-functional tablet mode and determine device parameters.
  *
  * @hdev:      HID device
- *
- * The specific string descriptor and data were discovered by sniffing
- * the Windows driver traffic.
  */
 static int huion_tablet_enable(struct hid_device *hdev)
 {
        int rc;
-       char buf[22];
+       struct usb_device *usb_dev = hid_to_usb_dev(hdev);
+       struct huion_drvdata *drvdata = hid_get_drvdata(hdev);
+       __le16 buf[6];
 
-       rc = usb_string(hid_to_usb_dev(hdev), 0x64, buf, sizeof(buf));
-       if (rc < 0)
-               return rc;
+       /*
+        * Read string descriptor containing tablet parameters. The specific
+        * string descriptor and data were discovered by sniffing the Windows
+        * driver traffic.
+        * NOTE: This enables fully-functional tablet mode.
+        */
+       rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+                               USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+                               (USB_DT_STRING << 8) + 0x64,
+                               0x0409, buf, sizeof(buf),
+                               USB_CTRL_GET_TIMEOUT);
+       if (rc == -EPIPE)
+               hid_warn(hdev, "device parameters not found\n");
+       else if (rc < 0)
+               hid_warn(hdev, "failed to get device parameters: %d\n", rc);
+       else if (rc != sizeof(buf))
+               hid_warn(hdev, "invalid device parameters\n");
+       else {
+               s32 params[HUION_PH_ID_NUM];
+               s32 resolution;
+               __u8 *p;
+               s32 v;
+
+               /* Extract device parameters */
+               params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]);
+               params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]);
+               params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]);
+               resolution = le16_to_cpu(buf[5]);
+               if (resolution == 0) {
+                       params[HUION_PH_ID_X_PM] = 0;
+                       params[HUION_PH_ID_Y_PM] = 0;
+               } else {
+                       params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
+                                                       1000 / resolution;
+                       params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
+                                                       1000 / resolution;
+               }
+
+               /* Allocate fixed report descriptor */
+               drvdata->rdesc = devm_kmalloc(&hdev->dev,
+                                       sizeof(huion_tablet_rdesc_template),
+                                       GFP_KERNEL);
+               if (drvdata->rdesc == NULL) {
+                       hid_err(hdev, "failed to allocate fixed rdesc\n");
+                       return -ENOMEM;
+               }
+               drvdata->rsize = sizeof(huion_tablet_rdesc_template);
+
+               /* Format fixed report descriptor */
+               memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
+                       drvdata->rsize);
+               for (p = drvdata->rdesc;
+                    p <= drvdata->rdesc + drvdata->rsize - 4;) {
+                       if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
+                           p[3] < sizeof(params)) {
+                               v = params[p[3]];
+                               put_unaligned(cpu_to_le32(v), (s32 *)p);
+                               p += 4;
+                       } else {
+                               p++;
+                       }
+               }
+       }
 
        return 0;
 }
 
 static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
-       int ret;
+       int rc;
        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+       struct huion_drvdata *drvdata;
+
+       /* Allocate and assign driver data */
+       drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
+       if (drvdata == NULL) {
+               hid_err(hdev, "failed to allocate driver data\n");
+               return -ENOMEM;
+       }
+       hid_set_drvdata(hdev, drvdata);
 
-       /* Ignore interfaces 1 (mouse) and 2 (keyboard) for Huion 580 tablet,
-        * as they are not used
-        */
        switch (id->product) {
-       case USB_DEVICE_ID_HUION_580:
-               if (intf->cur_altsetting->desc.bInterfaceNumber != 0x00)
-                       return -ENODEV;
+       case USB_DEVICE_ID_HUION_TABLET:
+               /* If this is the pen interface */
+               if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
+                       rc = huion_tablet_enable(hdev);
+                       if (rc) {
+                               hid_err(hdev, "tablet enabling failed\n");
+                               return rc;
+                       }
+               }
                break;
        }
 
-       ret = hid_parse(hdev);
-       if (ret) {
+       rc = hid_parse(hdev);
+       if (rc) {
                hid_err(hdev, "parse failed\n");
-               goto err;
+               return rc;
        }
 
-       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-       if (ret) {
+       rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (rc) {
                hid_err(hdev, "hw start failed\n");
-               goto err;
-       }
-
-       switch (id->product) {
-       case USB_DEVICE_ID_HUION_580:
-               ret = huion_tablet_enable(hdev);
-               if (ret) {
-                       hid_err(hdev, "tablet enabling failed\n");
-                       goto enabling_err;
-               }
-               break;
+               return rc;
        }
 
        return 0;
-enabling_err:
-       hid_hw_stop(hdev);
-err:
-       return ret;
 }
 
 static int huion_raw_event(struct hid_device *hdev, struct hid_report *report,
                        u8 *data, int size)
 {
-       /* If this is a pen input report then invert the in-range bit */
-       if (report->type == HID_INPUT_REPORT && report->id == 0x07 && size >= 2)
+       struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+
+       /* If this is a pen input report */
+       if (intf->cur_altsetting->desc.bInterfaceNumber == 0 &&
+           report->type == HID_INPUT_REPORT &&
+           report->id == 0x07 && size >= 2)
+               /* Invert the in-range bit */
                data[1] ^= 0x40;
 
        return 0;
 }
 
 static const struct hid_device_id huion_devices[] = {
-       { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, huion_devices);
index f52dbcb..31fad64 100644 (file)
@@ -308,6 +308,9 @@ static void mousevsc_on_receive(struct hv_device *device,
                memcpy(input_dev->input_buf, input_report->buffer, len);
                hid_input_report(input_dev->hid_device, HID_INPUT_REPORT,
                                 input_dev->input_buf, len, 1);
+
+               pm_wakeup_event(&input_dev->device->device, 0);
+
                break;
        default:
                pr_err("unsupported hid msg type - type %d len %d",
@@ -549,6 +552,8 @@ static int mousevsc_probe(struct hv_device *device,
                goto probe_err2;
        }
 
+       device_init_wakeup(&device->device, true);
+
        input_dev->connected = true;
        input_dev->init_complete = true;
 
@@ -571,6 +576,7 @@ static int mousevsc_remove(struct hv_device *dev)
 {
        struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
 
+       device_init_wakeup(&dev->device, false);
        vmbus_close(dev->channel);
        hid_hw_stop(input_dev->hid_device);
        hid_destroy_device(input_dev->hid_device);
index 315891d..d53bdda 100644 (file)
 #define USB_DEVICE_ID_UGCI_FIGHTING    0x0030
 
 #define USB_VENDOR_ID_HUION            0x256c
-#define USB_DEVICE_ID_HUION_580                0x006e
+#define USB_DEVICE_ID_HUION_TABLET     0x006e
 
 #define USB_VENDOR_ID_IDEACOM          0x1cb6
 #define USB_DEVICE_ID_IDEACOM_IDC6650  0x6650
 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A070    0xa070
 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072    0xa072
 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081    0xa081
+#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096 0xa096
 
 #define USB_VENDOR_ID_IMATION          0x0718
 #define USB_DEVICE_ID_DISC_STAKKA      0xd000
 #define USB_VENDOR_ID_JABRA            0x0b0e
 #define USB_DEVICE_ID_JABRA_SPEAK_410  0x0412
 #define USB_DEVICE_ID_JABRA_SPEAK_510  0x0420
+#define USB_DEVICE_ID_JABRA_GN9350E    0x9350
 
 #define USB_VENDOR_ID_JESS             0x0c45
 #define USB_DEVICE_ID_JESS_YUREX       0x1010
index 024cdf3..3c13af6 100644 (file)
@@ -883,16 +883,13 @@ void picolcd_exit_devfs(struct picolcd_data *data)
 
        dent = data->debug_reset;
        data->debug_reset = NULL;
-       if (dent)
-               debugfs_remove(dent);
+       debugfs_remove(dent);
        dent = data->debug_eeprom;
        data->debug_eeprom = NULL;
-       if (dent)
-               debugfs_remove(dent);
+       debugfs_remove(dent);
        dent = data->debug_flash;
        data->debug_flash = NULL;
-       if (dent)
-               debugfs_remove(dent);
+       debugfs_remove(dent);
        mutex_destroy(&data->mutex_flash);
 }
 
index 578bbe6..0dc2514 100644 (file)
@@ -377,7 +377,7 @@ static int rmi_input_event(struct hid_device *hdev, u8 *data, int size)
        irq_mask |= hdata->f30.irq_mask;
 
        if (data[1] & ~irq_mask)
-               hid_warn(hdev, "unknown intr source:%02lx %s:%d\n",
+               hid_dbg(hdev, "unknown intr source:%02lx %s:%d\n",
                        data[1] & ~irq_mask, __FILE__, __LINE__);
 
        if (hdata->f11.interrupt_base < hdata->f30.interrupt_base) {
@@ -400,7 +400,7 @@ static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size)
        struct rmi_data *hdata = hid_get_drvdata(hdev);
 
        if (!test_bit(RMI_READ_REQUEST_PENDING, &hdata->flags)) {
-               hid_err(hdev, "no read request pending\n");
+               hid_dbg(hdev, "no read request pending\n");
                return 0;
        }
 
@@ -549,10 +549,12 @@ static int rmi_populate_f11(struct hid_device *hdev)
        u8 buf[20];
        int ret;
        bool has_query9;
-       bool has_query10;
+       bool has_query10 = false;
        bool has_query11;
        bool has_query12;
        bool has_physical_props;
+       bool has_gestures;
+       bool has_rel;
        unsigned x_size, y_size;
        u16 query12_offset;
 
@@ -589,19 +591,32 @@ static int rmi_populate_f11(struct hid_device *hdev)
                return -ENODEV;
        }
 
-       /* query 8 to find out if query 10 exists */
-       ret = rmi_read(hdev, data->f11.query_base_addr + 8, buf);
-       if (ret) {
-               hid_err(hdev, "can not read gesture information: %d.\n", ret);
-               return ret;
+       has_rel = !!(buf[0] & BIT(3));
+       has_gestures = !!(buf[0] & BIT(5));
+
+       if (has_gestures) {
+               /* query 8 to find out if query 10 exists */
+               ret = rmi_read(hdev, data->f11.query_base_addr + 8, buf);
+               if (ret) {
+                       hid_err(hdev, "can not read gesture information: %d.\n",
+                               ret);
+                       return ret;
+               }
+               has_query10 = !!(buf[0] & BIT(2));
        }
-       has_query10 = !!(buf[0] & BIT(2));
 
        /*
-        * At least 8 queries are guaranteed to be present in F11
-        * +1 for query12.
+        * At least 4 queries are guaranteed to be present in F11
+        * +1 for query 5 which is present since absolute events are
+        * reported and +1 for query 12.
         */
-       query12_offset = 9;
+       query12_offset = 6;
+
+       if (has_rel)
+               ++query12_offset; /* query 6 is present */
+
+       if (has_gestures)
+               query12_offset += 2; /* query 7 and 8 are present */
 
        if (has_query9)
                ++query12_offset;
@@ -833,6 +848,8 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
        struct rmi_data *data = NULL;
        int ret;
        size_t alloc_size;
+       struct hid_report *input_report;
+       struct hid_report *output_report;
 
        data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL);
        if (!data)
@@ -851,12 +868,26 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
                return ret;
        }
 
-       data->input_report_size = (hdev->report_enum[HID_INPUT_REPORT]
-               .report_id_hash[RMI_ATTN_REPORT_ID]->size >> 3)
-               + 1 /* report id */;
-       data->output_report_size = (hdev->report_enum[HID_OUTPUT_REPORT]
-               .report_id_hash[RMI_WRITE_REPORT_ID]->size >> 3)
-               + 1 /* report id */;
+       input_report = hdev->report_enum[HID_INPUT_REPORT]
+                       .report_id_hash[RMI_ATTN_REPORT_ID];
+       if (!input_report) {
+               hid_err(hdev, "device does not have expected input report\n");
+               ret = -ENODEV;
+               return ret;
+       }
+
+       data->input_report_size = (input_report->size >> 3) + 1 /* report id */;
+
+       output_report = hdev->report_enum[HID_OUTPUT_REPORT]
+                       .report_id_hash[RMI_WRITE_REPORT_ID];
+       if (!output_report) {
+               hid_err(hdev, "device does not have expected output report\n");
+               ret = -ENODEV;
+               return ret;
+       }
+
+       data->output_report_size = (output_report->size >> 3)
+                                       + 1 /* report id */;
 
        alloc_size = data->output_report_size + data->input_report_size;
 
index 6adc0fa..65e2e76 100644 (file)
@@ -61,7 +61,7 @@ static ssize_t lua_sysfs_write(struct file *fp, struct kobject *kobj,
                return -EINVAL;
 
        mutex_lock(&lua->lua_lock);
-       retval = roccat_common2_send(usb_dev, command, (void *)buf, real_size);
+       retval = roccat_common2_send(usb_dev, command, buf, real_size);
        mutex_unlock(&lua->lua_lock);
 
        return retval ? retval : real_size;
index 2259eaa..c372368 100644 (file)
 
 #define MAX_LEDS 4
 
-static const u8 sixaxis_rdesc_fixup[] = {
-       0x95, 0x13, 0x09, 0x01, 0x81, 0x02, 0x95, 0x0C,
-       0x81, 0x01, 0x75, 0x10, 0x95, 0x04, 0x26, 0xFF,
-       0x03, 0x46, 0xFF, 0x03, 0x09, 0x01, 0x81, 0x02
-};
-
-static const u8 sixaxis_rdesc_fixup2[] = {
-       0x05, 0x01, 0x09, 0x04, 0xa1, 0x01, 0xa1, 0x02,
-       0x85, 0x01, 0x75, 0x08, 0x95, 0x01, 0x15, 0x00,
-       0x26, 0xff, 0x00, 0x81, 0x03, 0x75, 0x01, 0x95,
-       0x13, 0x15, 0x00, 0x25, 0x01, 0x35, 0x00, 0x45,
-       0x01, 0x05, 0x09, 0x19, 0x01, 0x29, 0x13, 0x81,
-       0x02, 0x75, 0x01, 0x95, 0x0d, 0x06, 0x00, 0xff,
-       0x81, 0x03, 0x15, 0x00, 0x26, 0xff, 0x00, 0x05,
-       0x01, 0x09, 0x01, 0xa1, 0x00, 0x75, 0x08, 0x95,
-       0x04, 0x35, 0x00, 0x46, 0xff, 0x00, 0x09, 0x30,
-       0x09, 0x31, 0x09, 0x32, 0x09, 0x35, 0x81, 0x02,
-       0xc0, 0x05, 0x01, 0x95, 0x13, 0x09, 0x01, 0x81,
-       0x02, 0x95, 0x0c, 0x81, 0x01, 0x75, 0x10, 0x95,
-       0x04, 0x26, 0xff, 0x03, 0x46, 0xff, 0x03, 0x09,
-       0x01, 0x81, 0x02, 0xc0, 0xa1, 0x02, 0x85, 0x02,
-       0x75, 0x08, 0x95, 0x30, 0x09, 0x01, 0xb1, 0x02,
-       0xc0, 0xa1, 0x02, 0x85, 0xee, 0x75, 0x08, 0x95,
-       0x30, 0x09, 0x01, 0xb1, 0x02, 0xc0, 0xa1, 0x02,
-       0x85, 0xef, 0x75, 0x08, 0x95, 0x30, 0x09, 0x01,
-       0xb1, 0x02, 0xc0, 0xc0,
+static __u8 sixaxis_rdesc[] = {
+       0x05, 0x01,         /*  Usage Page (Desktop),               */
+       0x09, 0x04,         /*  Usage (Joystik),                    */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0xA1, 0x02,         /*      Collection (Logical),           */
+       0x85, 0x01,         /*          Report ID (1),              */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x15, 0x00,         /*          Logical Minimum (0),        */
+       0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0x75, 0x01,         /*          Report Size (1),            */
+       0x95, 0x13,         /*          Report Count (19),          */
+       0x15, 0x00,         /*          Logical Minimum (0),        */
+       0x25, 0x01,         /*          Logical Maximum (1),        */
+       0x35, 0x00,         /*          Physical Minimum (0),       */
+       0x45, 0x01,         /*          Physical Maximum (1),       */
+       0x05, 0x09,         /*          Usage Page (Button),        */
+       0x19, 0x01,         /*          Usage Minimum (01h),        */
+       0x29, 0x13,         /*          Usage Maximum (13h),        */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x75, 0x01,         /*          Report Size (1),            */
+       0x95, 0x0D,         /*          Report Count (13),          */
+       0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0x15, 0x00,         /*          Logical Minimum (0),        */
+       0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
+       0x05, 0x01,         /*          Usage Page (Desktop),       */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0xA1, 0x00,         /*          Collection (Physical),      */
+       0x75, 0x08,         /*              Report Size (8),        */
+       0x95, 0x04,         /*              Report Count (4),       */
+       0x35, 0x00,         /*              Physical Minimum (0),   */
+       0x46, 0xFF, 0x00,   /*              Physical Maximum (255), */
+       0x09, 0x30,         /*              Usage (X),              */
+       0x09, 0x31,         /*              Usage (Y),              */
+       0x09, 0x32,         /*              Usage (Z),              */
+       0x09, 0x35,         /*              Usage (Rz),             */
+       0x81, 0x02,         /*              Input (Variable),       */
+       0xC0,               /*          End Collection,             */
+       0x05, 0x01,         /*          Usage Page (Desktop),       */
+       0x95, 0x13,         /*          Report Count (19),          */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x95, 0x0C,         /*          Report Count (12),          */
+       0x81, 0x01,         /*          Input (Constant),           */
+       0x75, 0x10,         /*          Report Size (16),           */
+       0x95, 0x04,         /*          Report Count (4),           */
+       0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+       0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0xC0,               /*      End Collection,                 */
+       0xA1, 0x02,         /*      Collection (Logical),           */
+       0x85, 0x02,         /*          Report ID (2),              */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x30,         /*          Report Count (48),          */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0xB1, 0x02,         /*          Feature (Variable),         */
+       0xC0,               /*      End Collection,                 */
+       0xA1, 0x02,         /*      Collection (Logical),           */
+       0x85, 0xEE,         /*          Report ID (238),            */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x30,         /*          Report Count (48),          */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0xB1, 0x02,         /*          Feature (Variable),         */
+       0xC0,               /*      End Collection,                 */
+       0xA1, 0x02,         /*      Collection (Logical),           */
+       0x85, 0xEF,         /*          Report ID (239),            */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x30,         /*          Report Count (48),          */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0xB1, 0x02,         /*          Feature (Variable),         */
+       0xC0,               /*      End Collection,                 */
+       0xC0                /*  End Collection                      */
 };
 
 /*
@@ -778,6 +827,13 @@ struct sony_sc {
        __u8 led_count;
 };
 
+static __u8 *sixaxis_fixup(struct hid_device *hdev, __u8 *rdesc,
+                            unsigned int *rsize)
+{
+       *rsize = sizeof(sixaxis_rdesc);
+       return sixaxis_rdesc;
+}
+
 static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc,
                             unsigned int *rsize)
 {
@@ -819,8 +875,6 @@ static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
        return 1;
 }
 
-
-/* Sony Vaio VGX has wrongly mouse pointer declared as constant */
 static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
@@ -857,20 +911,8 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                *rsize = sizeof(dualshock4_bt_rdesc);
        }
 
-       /* The HID descriptor exposed over BT has a trailing zero byte */
-       if ((((sc->quirks & SIXAXIS_CONTROLLER_USB) && *rsize == 148) ||
-                       ((sc->quirks & SIXAXIS_CONTROLLER_BT) && *rsize == 149)) &&
-                       rdesc[83] == 0x75) {
-               hid_info(hdev, "Fixing up Sony Sixaxis report descriptor\n");
-               memcpy((void *)&rdesc[83], (void *)&sixaxis_rdesc_fixup,
-                       sizeof(sixaxis_rdesc_fixup));
-       } else if (sc->quirks & SIXAXIS_CONTROLLER_USB &&
-                  *rsize > sizeof(sixaxis_rdesc_fixup2)) {
-               hid_info(hdev, "Sony Sixaxis clone detected. Using original report descriptor (size: %d clone; %d new)\n",
-                        *rsize, (int)sizeof(sixaxis_rdesc_fixup2));
-               *rsize = sizeof(sixaxis_rdesc_fixup2);
-               memcpy(rdesc, &sixaxis_rdesc_fixup2, *rsize);
-       }
+       if (sc->quirks & SIXAXIS_CONTROLLER)
+               return sixaxis_fixup(hdev, rdesc, rsize);
 
        if (sc->quirks & PS3REMOTE)
                return ps3remote_fixup(hdev, rdesc, rsize);
@@ -1307,7 +1349,7 @@ static int sony_leds_init(struct sony_sc *sc)
        static const char * const ds4_name_str[] = { "red", "green", "blue",
                                                  "global" };
        __u8 initial_values[MAX_LEDS] = { 0 };
-       __u8 max_brightness[MAX_LEDS] = { 1 };
+       __u8 max_brightness[MAX_LEDS] = { [0 ... (MAX_LEDS - 1)] = 1 };
        __u8 use_hw_blink[MAX_LEDS] = { 0 };
 
        BUG_ON(!(sc->quirks & SONY_LED_SUPPORT));
@@ -1830,9 +1872,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        if (sc->quirks & VAIO_RDESC_CONSTANT)
                connect_mask |= HID_CONNECT_HIDDEV_FORCE;
-       else if (sc->quirks & SIXAXIS_CONTROLLER_USB)
-               connect_mask |= HID_CONNECT_HIDDEV_FORCE;
-       else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
+       else if (sc->quirks & SIXAXIS_CONTROLLER)
                connect_mask |= HID_CONNECT_HIDDEV_FORCE;
 
        ret = hid_hw_start(hdev, connect_mask);
index 21aafc8..747d544 100644 (file)
@@ -1054,21 +1054,29 @@ static int i2c_hid_remove(struct i2c_client *client)
 static int i2c_hid_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
+       struct i2c_hid *ihid = i2c_get_clientdata(client);
+       struct hid_device *hid = ihid->hid;
+       int ret = 0;
 
        disable_irq(client->irq);
        if (device_may_wakeup(&client->dev))
                enable_irq_wake(client->irq);
 
+       if (hid->driver && hid->driver->suspend)
+               ret = hid->driver->suspend(hid, PMSG_SUSPEND);
+
        /* Save some power */
        i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
 
-       return 0;
+       return ret;
 }
 
 static int i2c_hid_resume(struct device *dev)
 {
        int ret;
        struct i2c_client *client = to_i2c_client(dev);
+       struct i2c_hid *ihid = i2c_get_clientdata(client);
+       struct hid_device *hid = ihid->hid;
 
        enable_irq(client->irq);
        ret = i2c_hid_hwreset(client);
@@ -1078,6 +1086,11 @@ static int i2c_hid_resume(struct device *dev)
        if (device_may_wakeup(&client->dev))
                disable_irq_wake(client->irq);
 
+       if (hid->driver && hid->driver->reset_resume) {
+               ret = hid->driver->reset_resume(hid);
+               return ret;
+       }
+
        return 0;
 }
 #endif
index 7b88f4c..79cf503 100644 (file)
@@ -58,7 +58,7 @@ module_param_named(ignoreled, ignoreled, uint, 0644);
 MODULE_PARM_DESC(ignoreled, "Autosuspend with active leds");
 
 /* Quirks specified at module load time */
-static char *quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL };
+static char *quirks_param[MAX_USBHID_BOOT_QUIRKS];
 module_param_array_named(quirks, quirks_param, charp, NULL, 0444);
 MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
                " quirks=vendorID:productID:quirks"
@@ -536,7 +536,8 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
        int head;
        struct usbhid_device *usbhid = hid->driver_data;
 
-       if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
+       if (((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) ||
+               test_bit(HID_DISCONNECTED, &usbhid->iofl))
                return;
 
        if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
@@ -1366,6 +1367,9 @@ static void usbhid_disconnect(struct usb_interface *intf)
                return;
 
        usbhid = hid->driver_data;
+       spin_lock_irq(&usbhid->lock);   /* Sync with error and led handlers */
+       set_bit(HID_DISCONNECTED, &usbhid->iofl);
+       spin_unlock_irq(&usbhid->lock);
        hid_destroy_device(hid);
        kfree(usbhid);
 }
index 31e6727..0dd5681 100644 (file)
@@ -124,6 +124,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096, HID_QUIRK_NO_INIT_INPUT_REPORTS },
 
        { 0, 0 }
 };