Merge branches 'for-4.4/upstream-fixes', 'for-4.5/async-suspend', 'for-4.5/container...
authorJiri Kosina <jkosina@suse.cz>
Thu, 14 Jan 2016 15:11:06 +0000 (16:11 +0100)
committerJiri Kosina <jkosina@suse.cz>
Thu, 14 Jan 2016 15:11:06 +0000 (16:11 +0100)
33 files changed:
MAINTAINERS
drivers/hid/hid-core.c
drivers/hid/hid-cp2112.c
drivers/hid/hid-debug.c
drivers/hid/hid-gt683r.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-lenovo.c
drivers/hid/hid-lg4ff.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-ntrig.c
drivers/hid/hid-picolcd_leds.c
drivers/hid/hid-prodikeys.c
drivers/hid/hid-roccat-arvo.c
drivers/hid/hid-roccat-common.c
drivers/hid/hid-roccat-isku.c
drivers/hid/hid-roccat-kone.c
drivers/hid/hid-roccat-koneplus.c
drivers/hid/hid-roccat-kovaplus.c
drivers/hid/hid-roccat-lua.c
drivers/hid/hid-roccat-pyra.c
drivers/hid/hid-sensor-hub.c
drivers/hid/hid-sony.c
drivers/hid/hid-steelseries.c
drivers/hid/hid-wiimote-modules.c
drivers/hid/hid-wiimote.h
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/usbhid/hid-core.c
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c
drivers/hid/wacom_wac.h
include/linux/hid.h

index cba790b..b81565b 100644 (file)
@@ -4984,6 +4984,7 @@ F:        arch/*/include/asm/suspend*.h
 
 HID CORE LAYER
 M:     Jiri Kosina <jikos@kernel.org>
+R:     Benjamin Tissoires <benjamin.tissoires@redhat.com>
 L:     linux-input@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
 S:     Maintained
@@ -11097,6 +11098,7 @@ F:      include/linux/usb/gadget*
 
 USB HID/HIDBP DRIVERS (USB KEYBOARDS, MICE, REMOTE CONTROLS, ...)
 M:     Jiri Kosina <jikos@kernel.org>
+R:     Benjamin Tissoires <benjamin.tissoires@redhat.com>
 L:     linux-usb@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
 S:     Maintained
index c6f7a69..7e89288 100644 (file)
@@ -625,7 +625,7 @@ static void hid_close_report(struct hid_device *device)
 
 static void hid_device_release(struct device *dev)
 {
-       struct hid_device *hid = container_of(dev, struct hid_device, dev);
+       struct hid_device *hid = to_hid_device(dev);
 
        hid_close_report(hid);
        kfree(hid->dev_rdesc);
@@ -1571,8 +1571,8 @@ read_report_descriptor(struct file *filp, struct kobject *kobj,
                struct bin_attribute *attr,
                char *buf, loff_t off, size_t count)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct device *dev = kobj_to_dev(kobj);
+       struct hid_device *hdev = to_hid_device(dev);
 
        if (off >= hdev->rsize)
                return 0;
@@ -1589,7 +1589,7 @@ static ssize_t
 show_country(struct device *dev, struct device_attribute *attr,
                char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
 
        return sprintf(buf, "%02x\n", hdev->country & 0xff);
 }
@@ -1691,11 +1691,6 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
                hid_warn(hdev,
                         "can't create sysfs country code attribute err: %d\n", ret);
 
-       ret = device_create_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
-       if (ret)
-               hid_warn(hdev,
-                        "can't create sysfs report descriptor attribute err: %d\n", ret);
-
        hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
                 buf, bus, hdev->version >> 8, hdev->version & 0xff,
                 type, hdev->name, hdev->phys);
@@ -1707,7 +1702,6 @@ EXPORT_SYMBOL_GPL(hid_connect);
 void hid_disconnect(struct hid_device *hdev)
 {
        device_remove_file(&hdev->dev, &dev_attr_country);
-       device_remove_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
        if (hdev->claimed & HID_CLAIMED_INPUT)
                hidinput_disconnect(hdev);
        if (hdev->claimed & HID_CLAIMED_HIDDEV)
@@ -1902,6 +1896,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
@@ -2076,7 +2071,7 @@ struct hid_dynid {
 static ssize_t store_new_id(struct device_driver *drv, const char *buf,
                size_t count)
 {
-       struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
+       struct hid_driver *hdrv = to_hid_driver(drv);
        struct hid_dynid *dynid;
        __u32 bus, vendor, product;
        unsigned long driver_data = 0;
@@ -2138,17 +2133,16 @@ static const struct hid_device_id *hid_match_device(struct hid_device *hdev,
 
 static int hid_bus_match(struct device *dev, struct device_driver *drv)
 {
-       struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_driver *hdrv = to_hid_driver(drv);
+       struct hid_device *hdev = to_hid_device(dev);
 
        return hid_match_device(hdev, hdrv) != NULL;
 }
 
 static int hid_device_probe(struct device *dev)
 {
-       struct hid_driver *hdrv = container_of(dev->driver,
-                       struct hid_driver, driver);
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_driver *hdrv = to_hid_driver(dev->driver);
+       struct hid_device *hdev = to_hid_device(dev);
        const struct hid_device_id *id;
        int ret = 0;
 
@@ -2190,7 +2184,7 @@ unlock_driver_lock:
 
 static int hid_device_remove(struct device *dev)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct hid_driver *hdrv;
        int ret = 0;
 
@@ -2223,12 +2217,9 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
                             char *buf)
 {
        struct hid_device *hdev = container_of(dev, struct hid_device, dev);
-       int len;
-
-       len = snprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n",
-                      hdev->bus, hdev->group, hdev->vendor, hdev->product);
 
-       return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+       return scnprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n",
+                        hdev->bus, hdev->group, hdev->vendor, hdev->product);
 }
 static DEVICE_ATTR_RO(modalias);
 
@@ -2236,11 +2227,19 @@ static struct attribute *hid_dev_attrs[] = {
        &dev_attr_modalias.attr,
        NULL,
 };
-ATTRIBUTE_GROUPS(hid_dev);
+static struct bin_attribute *hid_dev_bin_attrs[] = {
+       &dev_bin_attr_report_desc,
+       NULL
+};
+static const struct attribute_group hid_dev_group = {
+       .attrs = hid_dev_attrs,
+       .bin_attrs = hid_dev_bin_attrs,
+};
+__ATTRIBUTE_GROUPS(hid_dev);
 
 static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);   
 
        if (add_uevent_var(env, "HID_ID=%04X:%08X:%08X",
                        hdev->bus, hdev->vendor, hdev->product))
@@ -2408,6 +2407,7 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454_V2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20) },
@@ -2660,6 +2660,7 @@ struct hid_device *hid_allocate_device(void)
        device_initialize(&hdev->dev);
        hdev->dev.release = hid_device_release;
        hdev->dev.bus = &hid_bus_type;
+       device_enable_async_suspend(&hdev->dev);
 
        hid_close_report(hdev);
 
index 7afc3fc..7c38bfa 100644 (file)
@@ -807,7 +807,7 @@ static ssize_t name##_store(struct device *kdev, \
                            struct device_attribute *attr, const char *buf, \
                            size_t count) \
 { \
-       struct hid_device *hdev = container_of(kdev, struct hid_device, dev); \
+       struct hid_device *hdev = to_hid_device(kdev); \
        struct cp2112_usb_config_report cfg; \
        int ret = cp2112_get_usb_config(hdev, &cfg); \
        if (ret) \
@@ -822,7 +822,7 @@ static ssize_t name##_store(struct device *kdev, \
 static ssize_t name##_show(struct device *kdev, \
                           struct device_attribute *attr, char *buf) \
 { \
-       struct hid_device *hdev = container_of(kdev, struct hid_device, dev); \
+       struct hid_device *hdev = to_hid_device(kdev); \
        struct cp2112_usb_config_report cfg; \
        int ret = cp2112_get_usb_config(hdev, &cfg); \
        if (ret) \
@@ -887,7 +887,7 @@ static ssize_t pstr_store(struct device *kdev,
                          struct device_attribute *kattr, const char *buf,
                          size_t count)
 {
-       struct hid_device *hdev = container_of(kdev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(kdev);
        struct cp2112_pstring_attribute *attr =
                container_of(kattr, struct cp2112_pstring_attribute, attr);
        struct cp2112_string_report report;
@@ -918,7 +918,7 @@ static ssize_t pstr_store(struct device *kdev,
 static ssize_t pstr_show(struct device *kdev,
                         struct device_attribute *kattr, char *buf)
 {
-       struct hid_device *hdev = container_of(kdev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(kdev);
        struct cp2112_pstring_attribute *attr =
                container_of(kattr, struct cp2112_pstring_attribute, attr);
        struct cp2112_string_report report;
index 2886b64..acfb522 100644 (file)
@@ -659,13 +659,13 @@ EXPORT_SYMBOL_GPL(hid_dump_device);
 /* enqueue string to 'events' ring buffer */
 void hid_debug_event(struct hid_device *hdev, char *buf)
 {
-       int i;
+       unsigned i;
        struct hid_debug_list *list;
        unsigned long flags;
 
        spin_lock_irqsave(&hdev->debug_list_lock, flags);
        list_for_each_entry(list, &hdev->debug_list, node) {
-               for (i = 0; i < strlen(buf); i++)
+               for (i = 0; buf[i]; i++)
                        list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] =
                                buf[i];
                list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
index 0d6f135..a298fbd 100644 (file)
@@ -70,7 +70,7 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev,
 {
        int i;
        struct device *dev = led_cdev->dev->parent;
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct gt683r_led *led = hid_get_drvdata(hdev);
 
        for (i = 0; i < GT683R_LED_COUNT; i++) {
@@ -89,8 +89,7 @@ static ssize_t mode_show(struct device *dev,
                                char *buf)
 {
        u8 sysfs_mode;
-       struct hid_device *hdev = container_of(dev->parent,
-                                       struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev->parent);
        struct gt683r_led *led = hid_get_drvdata(hdev);
 
        if (led->mode == GT683R_LED_NORMAL)
@@ -108,8 +107,7 @@ static ssize_t mode_store(struct device *dev,
                                const char *buf, size_t count)
 {
        u8 sysfs_mode;
-       struct hid_device *hdev = container_of(dev->parent,
-                                       struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev->parent);
        struct gt683r_led *led = hid_get_drvdata(hdev);
 
 
index 9024a3d..242ec4f 100644 (file)
 #define USB_VENDOR_ID_ITE               0x048d
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA   0x8386
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA2  0x8350
+#define USB_DEVICE_ID_ITE_LENOVO_YOGA900       0x8396
 
 #define USB_VENDOR_ID_JABRA            0x0b0e
 #define USB_DEVICE_ID_JABRA_SPEAK_410  0x0412
 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2      0xc218
 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2    0xc219
 #define USB_DEVICE_ID_LOGITECH_G29_WHEEL       0xc24f
+#define USB_DEVICE_ID_LOGITECH_G920_WHEEL      0xc262
 #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D     0xc283
 #define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO     0xc286
 #define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940      0xc287
 #define USB_DEVICE_ID_PICOLCD          0xc002
 #define USB_DEVICE_ID_PICOLCD_BOOTLOADER       0xf002
 #define USB_DEVICE_ID_PICK16F1454      0x0042
+#define USB_DEVICE_ID_PICK16F1454_V2   0xf2f7
 
 #define USB_VENDOR_ID_MICROSOFT                0x045e
 #define USB_DEVICE_ID_SIDEWINDER_GV    0x003b
index 2ba6bf6..bcfaf32 100644 (file)
@@ -303,6 +303,7 @@ static enum power_supply_property hidinput_battery_props[] = {
 
 #define HID_BATTERY_QUIRK_PERCENT      (1 << 0) /* always reports percent */
 #define HID_BATTERY_QUIRK_FEATURE      (1 << 1) /* ask for feature report */
+#define HID_BATTERY_QUIRK_IGNORE       (1 << 2) /* completely ignore the battery */
 
 static const struct hid_device_id hid_battery_quirks[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
@@ -320,6 +321,9 @@ static const struct hid_device_id hid_battery_quirks[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
                USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
          HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM,
+               USB_DEVICE_ID_ELECOM_BM084),
+         HID_BATTERY_QUIRK_IGNORE },
        {}
 };
 
@@ -408,6 +412,14 @@ static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
        if (dev->battery != NULL)
                goto out;       /* already initialized? */
 
+       quirks = find_battery_quirk(dev);
+
+       hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",
+               dev->bus, dev->vendor, dev->product, dev->version, quirks);
+
+       if (quirks & HID_BATTERY_QUIRK_IGNORE)
+               goto out;
+
        psy_desc = kzalloc(sizeof(*psy_desc), GFP_KERNEL);
        if (psy_desc == NULL)
                goto out;
@@ -424,11 +436,6 @@ static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
        psy_desc->use_for_apm = 0;
        psy_desc->get_property = hidinput_get_battery_property;
 
-       quirks = find_battery_quirk(dev);
-
-       hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",
-               dev->bus, dev->vendor, dev->product, dev->version, quirks);
-
        min = field->logical_minimum;
        max = field->logical_maximum;
 
@@ -960,6 +967,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                goto ignore;
 
        case HID_UP_LOGIVENDOR:
+               /* intentional fallback */
+       case HID_UP_LOGIVENDOR2:
+               /* intentional fallback */
+       case HID_UP_LOGIVENDOR3:
                goto ignore;
 
        case HID_UP_PID:
index 8979f1f..0125e35 100644 (file)
@@ -220,7 +220,7 @@ static ssize_t attr_fn_lock_show_cptkbd(struct device *dev,
                struct device_attribute *attr,
                char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
 
        return snprintf(buf, PAGE_SIZE, "%u\n", cptkbd_data->fn_lock);
@@ -231,7 +231,7 @@ static ssize_t attr_fn_lock_store_cptkbd(struct device *dev,
                const char *buf,
                size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
        int value;
 
@@ -250,7 +250,7 @@ static ssize_t attr_sensitivity_show_cptkbd(struct device *dev,
                struct device_attribute *attr,
                char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
 
        return snprintf(buf, PAGE_SIZE, "%u\n",
@@ -262,7 +262,7 @@ static ssize_t attr_sensitivity_store_cptkbd(struct device *dev,
                const char *buf,
                size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
        int value;
 
@@ -387,7 +387,7 @@ static ssize_t attr_press_to_select_show_tpkbd(struct device *dev,
                struct device_attribute *attr,
                char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
 
        return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select);
@@ -398,7 +398,7 @@ static ssize_t attr_press_to_select_store_tpkbd(struct device *dev,
                const char *buf,
                size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
        int value;
 
@@ -417,7 +417,7 @@ static ssize_t attr_dragging_show_tpkbd(struct device *dev,
                struct device_attribute *attr,
                char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
 
        return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging);
@@ -428,7 +428,7 @@ static ssize_t attr_dragging_store_tpkbd(struct device *dev,
                const char *buf,
                size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
        int value;
 
@@ -447,7 +447,7 @@ static ssize_t attr_release_to_select_show_tpkbd(struct device *dev,
                struct device_attribute *attr,
                char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
 
        return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select);
@@ -458,7 +458,7 @@ static ssize_t attr_release_to_select_store_tpkbd(struct device *dev,
                const char *buf,
                size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
        int value;
 
@@ -477,7 +477,7 @@ static ssize_t attr_select_right_show_tpkbd(struct device *dev,
                struct device_attribute *attr,
                char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
 
        return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right);
@@ -488,7 +488,7 @@ static ssize_t attr_select_right_store_tpkbd(struct device *dev,
                const char *buf,
                size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
        int value;
 
@@ -507,7 +507,7 @@ static ssize_t attr_sensitivity_show_tpkbd(struct device *dev,
                struct device_attribute *attr,
                char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
 
        return snprintf(buf, PAGE_SIZE, "%u\n",
@@ -519,7 +519,7 @@ static ssize_t attr_sensitivity_store_tpkbd(struct device *dev,
                const char *buf,
                size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
        int value;
 
@@ -536,7 +536,7 @@ static ssize_t attr_press_speed_show_tpkbd(struct device *dev,
                struct device_attribute *attr,
                char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
 
        return snprintf(buf, PAGE_SIZE, "%u\n",
@@ -548,7 +548,7 @@ static ssize_t attr_press_speed_store_tpkbd(struct device *dev,
                const char *buf,
                size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
        int value;
 
@@ -609,7 +609,7 @@ static enum led_brightness lenovo_led_brightness_get_tpkbd(
                        struct led_classdev *led_cdev)
 {
        struct device *dev = led_cdev->dev->parent;
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
        int led_nr = 0;
 
@@ -625,7 +625,7 @@ static void lenovo_led_brightness_set_tpkbd(struct led_classdev *led_cdev,
                        enum led_brightness value)
 {
        struct device *dev = led_cdev->dev->parent;
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
        struct hid_report *report;
        int led_nr = 0;
index fbddcb3..af3a8ec 100644 (file)
@@ -33,8 +33,6 @@
 #include "hid-lg4ff.h"
 #include "hid-ids.h"
 
-#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
-
 #define LG4FF_MMODE_IS_MULTIMODE 0
 #define LG4FF_MMODE_SWITCHED 1
 #define LG4FF_MMODE_NOT_MULTIMODE 2
@@ -1020,7 +1018,7 @@ static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
                        enum led_brightness value)
 {
        struct device *dev = led_cdev->dev->parent;
-       struct hid_device *hid = container_of(dev, struct hid_device, dev);
+       struct hid_device *hid = to_hid_device(dev);
        struct lg_drv_data *drv_data = hid_get_drvdata(hid);
        struct lg4ff_device_entry *entry;
        int i, state = 0;
@@ -1055,7 +1053,7 @@ static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
 static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev)
 {
        struct device *dev = led_cdev->dev->parent;
-       struct hid_device *hid = container_of(dev, struct hid_device, dev);
+       struct hid_device *hid = to_hid_device(dev);
        struct lg_drv_data *drv_data = hid_get_drvdata(hid);
        struct lg4ff_device_entry *entry;
        int i, value = 0;
index 5fd9786..bd2ab47 100644 (file)
@@ -40,18 +40,22 @@ MODULE_PARM_DESC(disable_tap_to_click,
 
 #define REPORT_ID_HIDPP_SHORT                  0x10
 #define REPORT_ID_HIDPP_LONG                   0x11
+#define REPORT_ID_HIDPP_VERY_LONG              0x12
 
 #define HIDPP_REPORT_SHORT_LENGTH              7
 #define HIDPP_REPORT_LONG_LENGTH               20
+#define HIDPP_REPORT_VERY_LONG_LENGTH          64
 
 #define HIDPP_QUIRK_CLASS_WTP                  BIT(0)
 #define HIDPP_QUIRK_CLASS_M560                 BIT(1)
 #define HIDPP_QUIRK_CLASS_K400                 BIT(2)
+#define HIDPP_QUIRK_CLASS_G920                 BIT(3)
 
 /* bits 2..20 are reserved for classes */
 #define HIDPP_QUIRK_CONNECT_EVENTS             BIT(21)
 #define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS       BIT(22)
 #define HIDPP_QUIRK_NO_HIDINPUT                        BIT(23)
+#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS       BIT(24)
 
 #define HIDPP_QUIRK_DELAYED_INIT               (HIDPP_QUIRK_NO_HIDINPUT | \
                                                 HIDPP_QUIRK_CONNECT_EVENTS)
@@ -81,13 +85,13 @@ MODULE_PARM_DESC(disable_tap_to_click,
 struct fap {
        u8 feature_index;
        u8 funcindex_clientid;
-       u8 params[HIDPP_REPORT_LONG_LENGTH - 4U];
+       u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
 };
 
 struct rap {
        u8 sub_id;
        u8 reg_address;
-       u8 params[HIDPP_REPORT_LONG_LENGTH - 4U];
+       u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
 };
 
 struct hidpp_report {
@@ -144,8 +148,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
 static int __hidpp_send_report(struct hid_device *hdev,
                                struct hidpp_report *hidpp_report)
 {
+       struct hidpp_device *hidpp = hid_get_drvdata(hdev);
        int fields_count, ret;
 
+       hidpp = hid_get_drvdata(hdev);
+
        switch (hidpp_report->report_id) {
        case REPORT_ID_HIDPP_SHORT:
                fields_count = HIDPP_REPORT_SHORT_LENGTH;
@@ -153,6 +160,9 @@ static int __hidpp_send_report(struct hid_device *hdev,
        case REPORT_ID_HIDPP_LONG:
                fields_count = HIDPP_REPORT_LONG_LENGTH;
                break;
+       case REPORT_ID_HIDPP_VERY_LONG:
+               fields_count = HIDPP_REPORT_VERY_LONG_LENGTH;
+               break;
        default:
                return -ENODEV;
        }
@@ -163,9 +173,13 @@ static int __hidpp_send_report(struct hid_device *hdev,
         */
        hidpp_report->device_index = 0xff;
 
-       ret = hid_hw_raw_request(hdev, hidpp_report->report_id,
-               (u8 *)hidpp_report, fields_count, HID_OUTPUT_REPORT,
-               HID_REQ_SET_REPORT);
+       if (hidpp->quirks & HIDPP_QUIRK_FORCE_OUTPUT_REPORTS) {
+               ret = hid_hw_output_report(hdev, (u8 *)hidpp_report, fields_count);
+       } else {
+               ret = hid_hw_raw_request(hdev, hidpp_report->report_id,
+                       (u8 *)hidpp_report, fields_count, HID_OUTPUT_REPORT,
+                       HID_REQ_SET_REPORT);
+       }
 
        return ret == fields_count ? 0 : -1;
 }
@@ -217,8 +231,9 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
                goto exit;
        }
 
-       if (response->report_id == REPORT_ID_HIDPP_LONG &&
-           response->fap.feature_index == HIDPP20_ERROR) {
+       if ((response->report_id == REPORT_ID_HIDPP_LONG ||
+                       response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
+                       response->fap.feature_index == HIDPP20_ERROR) {
                ret = response->fap.params[1];
                dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
                goto exit;
@@ -243,7 +258,11 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
        message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
        if (!message)
                return -ENOMEM;
-       message->report_id = REPORT_ID_HIDPP_LONG;
+
+       if (param_count > (HIDPP_REPORT_LONG_LENGTH - 4))
+               message->report_id = REPORT_ID_HIDPP_VERY_LONG;
+       else
+               message->report_id = REPORT_ID_HIDPP_LONG;
        message->fap.feature_index = feat_index;
        message->fap.funcindex_clientid = funcindex_clientid;
        memcpy(&message->fap.params, params, param_count);
@@ -258,13 +277,23 @@ static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
        struct hidpp_report *response)
 {
        struct hidpp_report *message;
-       int ret;
+       int ret, max_count;
 
-       if ((report_id != REPORT_ID_HIDPP_SHORT) &&
-           (report_id != REPORT_ID_HIDPP_LONG))
+       switch (report_id) {
+       case REPORT_ID_HIDPP_SHORT:
+               max_count = HIDPP_REPORT_SHORT_LENGTH - 4;
+               break;
+       case REPORT_ID_HIDPP_LONG:
+               max_count = HIDPP_REPORT_LONG_LENGTH - 4;
+               break;
+       case REPORT_ID_HIDPP_VERY_LONG:
+               max_count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
+               break;
+       default:
                return -EINVAL;
+       }
 
-       if (param_count > sizeof(message->rap.params))
+       if (param_count > max_count)
                return -EINVAL;
 
        message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
@@ -508,10 +537,19 @@ static int hidpp_devicenametype_get_device_name(struct hidpp_device *hidpp,
        if (ret)
                return ret;
 
-       if (response.report_id == REPORT_ID_HIDPP_LONG)
+       switch (response.report_id) {
+       case REPORT_ID_HIDPP_VERY_LONG:
+               count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
+               break;
+       case REPORT_ID_HIDPP_LONG:
                count = HIDPP_REPORT_LONG_LENGTH - 4;
-       else
+               break;
+       case REPORT_ID_HIDPP_SHORT:
                count = HIDPP_REPORT_SHORT_LENGTH - 4;
+               break;
+       default:
+               return -EPROTO;
+       }
 
        if (len_buf < count)
                count = len_buf;
@@ -1257,6 +1295,131 @@ static int k400_connect(struct hid_device *hdev, bool connected)
        return k400_disable_tap_to_click(hidpp);
 }
 
+/* ------------------------------------------------------------------------- */
+/* Logitech G920 Driving Force Racing Wheel for Xbox One                     */
+/* ------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_G920_FORCE_FEEDBACK                 0x8123
+
+/* Using session ID = 1 */
+#define CMD_G920_FORCE_GET_APERTURE                    0x51
+#define CMD_G920_FORCE_SET_APERTURE                    0x61
+
+struct g920_private_data {
+       u8 force_feature;
+       u16 range;
+};
+
+static ssize_t g920_range_show(struct device *dev, struct device_attribute *attr,
+                               char *buf)
+{
+       struct hid_device *hid = to_hid_device(dev);
+       struct hidpp_device *hidpp = hid_get_drvdata(hid);
+       struct g920_private_data *pdata;
+
+       pdata = hidpp->private_data;
+       if (!pdata) {
+               hid_err(hid, "Private driver data not found!\n");
+               return -EINVAL;
+       }
+
+       return scnprintf(buf, PAGE_SIZE, "%u\n", pdata->range);
+}
+
+static ssize_t g920_range_store(struct device *dev, struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct hid_device *hid = to_hid_device(dev);
+       struct hidpp_device *hidpp = hid_get_drvdata(hid);
+       struct g920_private_data *pdata;
+       struct hidpp_report response;
+       u8 params[2];
+       int ret;
+       u16 range = simple_strtoul(buf, NULL, 10);
+
+       pdata = hidpp->private_data;
+       if (!pdata) {
+               hid_err(hid, "Private driver data not found!\n");
+               return -EINVAL;
+       }
+
+       if (range < 180)
+               range = 180;
+       else if (range > 900)
+               range = 900;
+
+       params[0] = range >> 8;
+       params[1] = range & 0x00FF;
+
+       ret = hidpp_send_fap_command_sync(hidpp, pdata->force_feature,
+               CMD_G920_FORCE_SET_APERTURE, params, 2, &response);
+       if (ret)
+               return ret;
+
+       pdata->range = range;
+       return count;
+}
+
+static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, g920_range_show, g920_range_store);
+
+static int g920_allocate(struct hid_device *hdev)
+{
+       struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+       struct g920_private_data *pdata;
+
+       pdata = devm_kzalloc(&hdev->dev, sizeof(struct g920_private_data),
+                       GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       hidpp->private_data = pdata;
+
+       return 0;
+}
+
+static int g920_get_config(struct hidpp_device *hidpp)
+{
+       struct g920_private_data *pdata = hidpp->private_data;
+       struct hidpp_report response;
+       u8 feature_type;
+       u8 feature_index;
+       int ret;
+
+       pdata = hidpp->private_data;
+       if (!pdata) {
+               hid_err(hidpp->hid_dev, "Private driver data not found!\n");
+               return -EINVAL;
+       }
+
+       /* Find feature and store for later use */
+       ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_G920_FORCE_FEEDBACK,
+               &feature_index, &feature_type);
+       if (ret)
+               return ret;
+
+       pdata->force_feature = feature_index;
+
+       /* Read current Range */
+       ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+               CMD_G920_FORCE_GET_APERTURE, NULL, 0, &response);
+       if (ret > 0) {
+               hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
+                       __func__, ret);
+               return -EPROTO;
+       }
+       if (ret)
+               return ret;
+
+       pdata->range = get_unaligned_be16(&response.fap.params[0]);
+
+       /* Create sysfs interface */
+       ret = device_create_file(&(hidpp->hid_dev->dev), &dev_attr_range);
+       if (ret)
+               hid_warn(hidpp->hid_dev, "Unable to create sysfs interface for \"range\", errno %d\n", ret);
+
+       return 0;
+}
+
 /* -------------------------------------------------------------------------- */
 /* Generic HID++ devices                                                      */
 /* -------------------------------------------------------------------------- */
@@ -1276,6 +1439,25 @@ static int hidpp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        return 0;
 }
 
+static int hidpp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+
+       /* Ensure that Logitech G920 is not given a default fuzz/flat value */
+       if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+               if (usage->type == EV_ABS && (usage->code == ABS_X ||
+                               usage->code == ABS_Y || usage->code == ABS_Z ||
+                               usage->code == ABS_RZ)) {
+                       field->application = HID_GD_MULTIAXIS;
+               }
+       }
+
+       return 0;
+}
+
+
 static void hidpp_populate_input(struct hidpp_device *hidpp,
                struct input_dev *input, bool origin_is_hid_core)
 {
@@ -1347,6 +1529,14 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
 
        /* Generic HID++ processing. */
        switch (data[0]) {
+       case REPORT_ID_HIDPP_VERY_LONG:
+               if (size != HIDPP_REPORT_VERY_LONG_LENGTH) {
+                       hid_err(hdev, "received hid++ report of bad size (%d)",
+                               size);
+                       return 1;
+               }
+               ret = hidpp_raw_hidpp_event(hidpp, data, size);
+               break;
        case REPORT_ID_HIDPP_LONG:
                if (size != HIDPP_REPORT_LONG_LENGTH) {
                        hid_err(hdev, "received hid++ report of bad size (%d)",
@@ -1393,10 +1583,12 @@ static void hidpp_overwrite_name(struct hid_device *hdev, bool use_unifying)
        else
                name = hidpp_get_device_name(hidpp);
 
-       if (!name)
+       if (!name) {
                hid_err(hdev, "unable to retrieve the name of the device");
-       else
+       } else {
+               dbg_hid("HID++: Got name: %s\n", name);
                snprintf(hdev->name, sizeof(hdev->name), "%s", name);
+       }
 
        kfree(name);
 }
@@ -1547,6 +1739,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
                ret = k400_allocate(hdev);
                if (ret)
                        goto allocate_fail;
+       } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+               ret = g920_allocate(hdev);
+               if (ret)
+                       goto allocate_fail;
        }
 
        INIT_WORK(&hidpp->work, delayed_work_cb);
@@ -1559,6 +1755,25 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
                goto hid_parse_fail;
        }
 
+       if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
+               connect_mask &= ~HID_CONNECT_HIDINPUT;
+
+       if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+               ret = hid_hw_start(hdev, connect_mask);
+               if (ret) {
+                       hid_err(hdev, "hw start failed\n");
+                       goto hid_hw_start_fail;
+               }
+               ret = hid_hw_open(hdev);
+               if (ret < 0) {
+                       dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
+                               __func__, ret);
+                       hid_hw_stop(hdev);
+                       goto hid_hw_start_fail;
+               }
+       }
+
+
        /* Allow incoming packets */
        hid_device_io_start(hdev);
 
@@ -1567,8 +1782,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
                if (!connected) {
                        ret = -ENODEV;
                        hid_err(hdev, "Device not connected");
-                       hid_device_io_stop(hdev);
-                       goto hid_parse_fail;
+                       goto hid_hw_open_failed;
                }
 
                hid_info(hdev, "HID++ %u.%u device connected.\n",
@@ -1581,19 +1795,22 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
                ret = wtp_get_config(hidpp);
                if (ret)
-                       goto hid_parse_fail;
+                       goto hid_hw_open_failed;
+       } else if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
+               ret = g920_get_config(hidpp);
+               if (ret)
+                       goto hid_hw_open_failed;
        }
 
        /* Block incoming packets */
        hid_device_io_stop(hdev);
 
-       if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
-               connect_mask &= ~HID_CONNECT_HIDINPUT;
-
-       ret = hid_hw_start(hdev, connect_mask);
-       if (ret) {
-               hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
-               goto hid_hw_start_fail;
+       if (!(hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
+               ret = hid_hw_start(hdev, connect_mask);
+               if (ret) {
+                       hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
+                       goto hid_hw_start_fail;
+               }
        }
 
        if (hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) {
@@ -1605,6 +1822,13 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        return ret;
 
+hid_hw_open_failed:
+       hid_device_io_stop(hdev);
+       if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+               device_remove_file(&hdev->dev, &dev_attr_range);
+               hid_hw_close(hdev);
+               hid_hw_stop(hdev);
+       }
 hid_hw_start_fail:
 hid_parse_fail:
        cancel_work_sync(&hidpp->work);
@@ -1618,9 +1842,13 @@ static void hidpp_remove(struct hid_device *hdev)
 {
        struct hidpp_device *hidpp = hid_get_drvdata(hdev);
 
+       if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+               device_remove_file(&hdev->dev, &dev_attr_range);
+               hid_hw_close(hdev);
+       }
+       hid_hw_stop(hdev);
        cancel_work_sync(&hidpp->work);
        mutex_destroy(&hidpp->send_mutex);
-       hid_hw_stop(hdev);
 }
 
 static const struct hid_device_id hidpp_devices[] = {
@@ -1648,6 +1876,9 @@ static const struct hid_device_id hidpp_devices[] = {
 
        { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
                USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
+
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
+               .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
        {}
 };
 
@@ -1661,6 +1892,7 @@ static struct hid_driver hidpp_driver = {
        .raw_event = hidpp_raw_event,
        .input_configured = hidpp_input_configured,
        .input_mapping = hidpp_input_mapping,
+       .input_mapped = hidpp_input_mapped,
 };
 
 module_hid_driver(hidpp_driver);
index 3d664d0..296d499 100644 (file)
@@ -272,7 +272,7 @@ static ssize_t mt_show_quirks(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct mt_device *td = hid_get_drvdata(hdev);
 
        return sprintf(buf, "%u\n", td->mtclass.quirks);
@@ -282,7 +282,7 @@ static ssize_t mt_set_quirks(struct device *dev,
                          struct device_attribute *attr,
                          const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct mt_device *td = hid_get_drvdata(hdev);
 
        unsigned long val;
@@ -357,8 +357,19 @@ static void mt_feature_mapping(struct hid_device *hdev,
                        break;
                }
 
-               td->inputmode = field->report->id;
-               td->inputmode_index = usage->usage_index;
+               if (td->inputmode < 0) {
+                       td->inputmode = field->report->id;
+                       td->inputmode_index = usage->usage_index;
+               } else {
+                       /*
+                        * Some elan panels wrongly declare 2 input mode
+                        * features, and silently ignore when we set the
+                        * value in the second field. Skip the second feature
+                        * and hope for the best.
+                        */
+                       dev_info(&hdev->dev,
+                                "Ignoring the extra HID_DG_INPUTMODE\n");
+               }
 
                break;
        case HID_DG_CONTACTMAX:
@@ -486,6 +497,11 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        mt_store_field(usage, td, hi);
                        return 1;
                case HID_DG_CONFIDENCE:
+                       if (cls->name == MT_CLS_WIN_8 &&
+                               field->application == HID_DG_TOUCHPAD) {
+                               cls->quirks &= ~MT_QUIRK_ALWAYS_VALID;
+                               cls->quirks |= MT_QUIRK_VALID_IS_CONFIDENCE;
+                       }
                        mt_store_field(usage, td, hi);
                        return 1;
                case HID_DG_TIPSWITCH:
index 756d1ef..1b0084d 100644 (file)
@@ -173,7 +173,7 @@ static ssize_t show_phys_width(struct device *dev,
                               struct device_attribute *attr,
                               char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        return sprintf(buf, "%d\n", nd->sensor_physical_width);
@@ -185,7 +185,7 @@ static ssize_t show_phys_height(struct device *dev,
                                struct device_attribute *attr,
                                char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        return sprintf(buf, "%d\n", nd->sensor_physical_height);
@@ -197,7 +197,7 @@ static ssize_t show_log_width(struct device *dev,
                              struct device_attribute *attr,
                              char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        return sprintf(buf, "%d\n", nd->sensor_logical_width);
@@ -209,7 +209,7 @@ static ssize_t show_log_height(struct device *dev,
                               struct device_attribute *attr,
                               char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        return sprintf(buf, "%d\n", nd->sensor_logical_height);
@@ -221,7 +221,7 @@ static ssize_t show_min_width(struct device *dev,
                              struct device_attribute *attr,
                              char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        return sprintf(buf, "%d\n", nd->min_width *
@@ -233,7 +233,7 @@ static ssize_t set_min_width(struct device *dev,
                             struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        unsigned long val;
@@ -256,7 +256,7 @@ static ssize_t show_min_height(struct device *dev,
                               struct device_attribute *attr,
                               char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        return sprintf(buf, "%d\n", nd->min_height *
@@ -268,7 +268,7 @@ static ssize_t set_min_height(struct device *dev,
                              struct device_attribute *attr,
                              const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        unsigned long val;
@@ -292,7 +292,7 @@ static ssize_t show_activate_slack(struct device *dev,
                                   struct device_attribute *attr,
                                   char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        return sprintf(buf, "%d\n", nd->activate_slack);
@@ -302,7 +302,7 @@ static ssize_t set_activate_slack(struct device *dev,
                                  struct device_attribute *attr,
                                  const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        unsigned long val;
@@ -325,7 +325,7 @@ static ssize_t show_activation_width(struct device *dev,
                                     struct device_attribute *attr,
                                     char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        return sprintf(buf, "%d\n", nd->activation_width *
@@ -337,7 +337,7 @@ static ssize_t set_activation_width(struct device *dev,
                                    struct device_attribute *attr,
                                    const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        unsigned long val;
@@ -361,7 +361,7 @@ static ssize_t show_activation_height(struct device *dev,
                                      struct device_attribute *attr,
                                      char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        return sprintf(buf, "%d\n", nd->activation_height *
@@ -373,7 +373,7 @@ static ssize_t set_activation_height(struct device *dev,
                                     struct device_attribute *attr,
                                     const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        unsigned long val;
@@ -397,7 +397,7 @@ static ssize_t show_deactivate_slack(struct device *dev,
                                     struct device_attribute *attr,
                                     char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        return sprintf(buf, "%d\n", -nd->deactivate_slack);
@@ -407,7 +407,7 @@ static ssize_t set_deactivate_slack(struct device *dev,
                                    struct device_attribute *attr,
                                    const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct ntrig_data *nd = hid_get_drvdata(hdev);
 
        unsigned long val;
index e994f9c..a802b4f 100644 (file)
@@ -66,7 +66,7 @@ static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
        int i, state = 0;
 
        dev  = led_cdev->dev->parent;
-       hdev = container_of(dev, struct hid_device, dev);
+       hdev = to_hid_device(dev);
        data = hid_get_drvdata(hdev);
        if (!data)
                return;
@@ -93,7 +93,7 @@ static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_c
        int i, value = 0;
 
        dev  = led_cdev->dev->parent;
-       hdev = container_of(dev, struct hid_device, dev);
+       hdev = to_hid_device(dev);
        data = hid_get_drvdata(hdev);
        for (i = 0; i < 8; i++)
                if (led_cdev == data->led[i]) {
index 3a207c0..f095bf8 100644 (file)
@@ -103,7 +103,7 @@ MODULE_PARM_DESC(enable, "Enable for the PC-MIDI virtual audio driver");
 static ssize_t show_channel(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct pk_device *pk = hid_get_drvdata(hdev);
 
        dbg_hid("pcmidi sysfs read channel=%u\n", pk->pm->midi_channel);
@@ -116,7 +116,7 @@ static ssize_t show_channel(struct device *dev,
 static ssize_t store_channel(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct pk_device *pk = hid_get_drvdata(hdev);
 
        unsigned channel = 0;
@@ -140,7 +140,7 @@ static struct device_attribute *sysfs_device_attr_channel = {
 static ssize_t show_sustain(struct device *dev,
  struct device_attribute *attr, char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct pk_device *pk = hid_get_drvdata(hdev);
 
        dbg_hid("pcmidi sysfs read sustain=%u\n", pk->pm->midi_sustain);
@@ -153,7 +153,7 @@ static ssize_t show_sustain(struct device *dev,
 static ssize_t store_sustain(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct pk_device *pk = hid_get_drvdata(hdev);
 
        unsigned sustain = 0;
@@ -179,7 +179,7 @@ static struct device_attribute *sysfs_device_attr_sustain = {
 static ssize_t show_octave(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct pk_device *pk = hid_get_drvdata(hdev);
 
        dbg_hid("pcmidi sysfs read octave=%d\n", pk->pm->midi_octave);
@@ -192,7 +192,7 @@ static ssize_t show_octave(struct device *dev,
 static ssize_t store_octave(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct pk_device *pk = hid_get_drvdata(hdev);
 
        int octave = 0;
index 1948208..329c5d1 100644 (file)
@@ -191,8 +191,7 @@ static ssize_t arvo_sysfs_write(struct file *fp,
                struct kobject *kobj, void const *buf,
                loff_t off, size_t count, size_t real_size, uint command)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
@@ -211,8 +210,7 @@ static ssize_t arvo_sysfs_read(struct file *fp,
                struct kobject *kobj, void *buf, loff_t off,
                size_t count, size_t real_size, uint command)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
index 02e28e9..8155ac5 100644 (file)
@@ -134,8 +134,7 @@ ssize_t roccat_common2_sysfs_read(struct file *fp, struct kobject *kobj,
                char *buf, loff_t off, size_t count,
                size_t real_size, uint command)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
@@ -158,8 +157,7 @@ ssize_t roccat_common2_sysfs_write(struct file *fp, struct kobject *kobj,
                void const *buf, loff_t off, size_t count,
                size_t real_size, uint command)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
index bc62ed9..02db537 100644 (file)
@@ -121,8 +121,7 @@ static ssize_t isku_sysfs_read(struct file *fp, struct kobject *kobj,
                char *buf, loff_t off, size_t count,
                size_t real_size, uint command)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
@@ -144,8 +143,7 @@ static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj,
                void const *buf, loff_t off, size_t count,
                size_t real_size, uint command)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
index c292650..bf4675a 100644 (file)
@@ -269,8 +269,7 @@ static int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
 static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
 
        if (off >= sizeof(struct kone_settings))
@@ -294,8 +293,7 @@ static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
 static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval = 0, difference, old_profile;
@@ -332,8 +330,7 @@ static BIN_ATTR(settings, 0660, kone_sysfs_read_settings,
 static ssize_t kone_sysfs_read_profilex(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr,
                char *buf, loff_t off, size_t count) {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
 
        if (off >= sizeof(struct kone_profile))
@@ -353,8 +350,7 @@ static ssize_t kone_sysfs_read_profilex(struct file *fp,
 static ssize_t kone_sysfs_write_profilex(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr,
                char *buf, loff_t off, size_t count) {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        struct kone_profile *profile;
index 5e99fcd..09e8fc7 100644 (file)
@@ -87,8 +87,7 @@ static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
                char *buf, loff_t off, size_t count,
                size_t real_size, uint command)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
@@ -113,8 +112,7 @@ static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
                void const *buf, loff_t off, size_t count,
                size_t real_size, uint command)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
@@ -193,8 +191,7 @@ static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        ssize_t retval;
 
@@ -212,8 +209,7 @@ static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        ssize_t retval;
 
index 9660477..43617fb 100644 (file)
@@ -128,8 +128,7 @@ static ssize_t kovaplus_sysfs_read(struct file *fp, struct kobject *kobj,
                char *buf, loff_t off, size_t count,
                size_t real_size, uint command)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
@@ -154,8 +153,7 @@ static ssize_t kovaplus_sysfs_write(struct file *fp, struct kobject *kobj,
                void const *buf, loff_t off, size_t count,
                size_t real_size, uint command)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
@@ -221,8 +219,7 @@ static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        ssize_t retval;
 
@@ -240,8 +237,7 @@ static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        ssize_t retval;
 
index 65e2e76..ac1a731 100644 (file)
@@ -30,7 +30,7 @@ static ssize_t lua_sysfs_read(struct file *fp, struct kobject *kobj,
                char *buf, loff_t off, size_t count,
                size_t real_size, uint command)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct lua_device *lua = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
@@ -52,7 +52,7 @@ static ssize_t lua_sysfs_write(struct file *fp, struct kobject *kobj,
                void const *buf, loff_t off, size_t count,
                size_t real_size, uint command)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct lua_device *lua = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
index 47d7e74..b30aa7b 100644 (file)
@@ -90,8 +90,7 @@ static ssize_t pyra_sysfs_read(struct file *fp, struct kobject *kobj,
                char *buf, loff_t off, size_t count,
                size_t real_size, uint command)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
@@ -116,8 +115,7 @@ static ssize_t pyra_sysfs_write(struct file *fp, struct kobject *kobj,
                void const *buf, loff_t off, size_t count,
                size_t real_size, uint command)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval;
@@ -191,8 +189,7 @@ static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        ssize_t retval;
 
@@ -210,8 +207,7 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        ssize_t retval;
 
@@ -248,8 +244,7 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
                loff_t off, size_t count)
 {
-       struct device *dev =
-                       container_of(kobj, struct device, kobj)->parent->parent;
+       struct device *dev = kobj_to_dev(kobj)->parent->parent;
        struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
        int retval = 0;
index 92870cd..58ed8f2 100644 (file)
@@ -794,6 +794,9 @@ static const struct hid_device_id sensor_hub_devices[] = {
        { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
                        USB_DEVICE_ID_ITE_LENOVO_YOGA2),
                        .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+       { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
+                       USB_DEVICE_ID_ITE_LENOVO_YOGA900),
+                       .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
        { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
                     HID_ANY_ID) },
        { }
index 774cd22..9b8db0e 100644 (file)
@@ -1028,6 +1028,7 @@ struct sony_sc {
        struct led_classdev *leds[MAX_LEDS];
        unsigned long quirks;
        struct work_struct state_worker;
+       void(*send_output_report)(struct sony_sc*);
        struct power_supply *battery;
        struct power_supply_desc battery_desc;
        int device_id;
@@ -1044,6 +1045,7 @@ struct sony_sc {
        __u8 battery_charging;
        __u8 battery_capacity;
        __u8 led_state[MAX_LEDS];
+       __u8 resume_led_state[MAX_LEDS];
        __u8 led_delay_on[MAX_LEDS];
        __u8 led_delay_off[MAX_LEDS];
        __u8 led_count;
@@ -1137,11 +1139,11 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
         * the gyroscope values to corresponding axes so we need a
         * modified one.
         */
-       if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && *rsize == 467) {
+       if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
                hid_info(hdev, "Using modified Dualshock 4 report descriptor with gyroscope axes\n");
                rdesc = dualshock4_usb_rdesc;
                *rsize = sizeof(dualshock4_usb_rdesc);
-       } else if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) && *rsize == 357) {
+       } else if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
                hid_info(hdev, "Using modified Dualshock 4 Bluetooth report descriptor\n");
                rdesc = dualshock4_bt_rdesc;
                *rsize = sizeof(dualshock4_bt_rdesc);
@@ -1549,7 +1551,7 @@ static void sony_led_set_brightness(struct led_classdev *led,
                                    enum led_brightness value)
 {
        struct device *dev = led->dev->parent;
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct sony_sc *drv_data;
 
        int n;
@@ -1591,7 +1593,7 @@ static void sony_led_set_brightness(struct led_classdev *led,
 static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
 {
        struct device *dev = led->dev->parent;
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct sony_sc *drv_data;
 
        int n;
@@ -1614,7 +1616,7 @@ static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on,
                                unsigned long *delay_off)
 {
        struct device *dev = led->dev->parent;
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct sony_sc *drv_data = hid_get_drvdata(hdev);
        int n;
        __u8 new_on, new_off;
@@ -1789,7 +1791,7 @@ error_leds:
        return ret;
 }
 
-static void sixaxis_state_worker(struct work_struct *work)
+static void sixaxis_send_output_report(struct sony_sc *sc)
 {
        static const union sixaxis_output_report_01 default_report = {
                .buf = {
@@ -1803,7 +1805,6 @@ static void sixaxis_state_worker(struct work_struct *work)
                        0x00, 0x00, 0x00, 0x00, 0x00
                }
        };
-       struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
        struct sixaxis_output_report *report =
                (struct sixaxis_output_report *)sc->output_report_dmabuf;
        int n;
@@ -1846,9 +1847,8 @@ static void sixaxis_state_worker(struct work_struct *work)
                        HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
 }
 
-static void dualshock4_state_worker(struct work_struct *work)
+static void dualshock4_send_output_report(struct sony_sc *sc)
 {
-       struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
        struct hid_device *hdev = sc->hdev;
        __u8 *buf = sc->output_report_dmabuf;
        int offset;
@@ -1893,9 +1893,8 @@ static void dualshock4_state_worker(struct work_struct *work)
                                HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
 }
 
-static void motion_state_worker(struct work_struct *work)
+static void motion_send_output_report(struct sony_sc *sc)
 {
-       struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
        struct hid_device *hdev = sc->hdev;
        struct motion_output_report_02 *report =
                (struct motion_output_report_02 *)sc->output_report_dmabuf;
@@ -1914,6 +1913,18 @@ static void motion_state_worker(struct work_struct *work)
        hid_hw_output_report(hdev, (__u8 *)report, MOTION_REPORT_0x02_SIZE);
 }
 
+static inline void sony_send_output_report(struct sony_sc *sc)
+{
+       if (sc->send_output_report)
+               sc->send_output_report(sc);
+}
+
+static void sony_state_worker(struct work_struct *work)
+{
+       struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
+       sc->send_output_report(sc);
+}
+
 static int sony_allocate_output_report(struct sony_sc *sc)
 {
        if ((sc->quirks & SIXAXIS_CONTROLLER) ||
@@ -2241,11 +2252,13 @@ static void sony_release_device_id(struct sony_sc *sc)
        }
 }
 
-static inline void sony_init_work(struct sony_sc *sc,
-                                       void (*worker)(struct work_struct *))
+static inline void sony_init_output_report(struct sony_sc *sc,
+                               void(*send_output_report)(struct sony_sc*))
 {
+       sc->send_output_report = send_output_report;
+
        if (!sc->worker_initialized)
-               INIT_WORK(&sc->state_worker, worker);
+               INIT_WORK(&sc->state_worker, sony_state_worker);
 
        sc->worker_initialized = 1;
 }
@@ -2319,7 +2332,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
                hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
                ret = sixaxis_set_operational_usb(hdev);
-               sony_init_work(sc, sixaxis_state_worker);
+               sony_init_output_report(sc, sixaxis_send_output_report);
        } else if ((sc->quirks & SIXAXIS_CONTROLLER_BT) ||
                        (sc->quirks & NAVIGATION_CONTROLLER_BT)) {
                /*
@@ -2328,7 +2341,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                 */
                hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
                ret = sixaxis_set_operational_bt(hdev);
-               sony_init_work(sc, sixaxis_state_worker);
+               sony_init_output_report(sc, sixaxis_send_output_report);
        } else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
                if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
                        /*
@@ -2343,9 +2356,9 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                        }
                }
 
-               sony_init_work(sc, dualshock4_state_worker);
+               sony_init_output_report(sc, dualshock4_send_output_report);
        } else if (sc->quirks & MOTION_CONTROLLER) {
-               sony_init_work(sc, motion_state_worker);
+               sony_init_output_report(sc, motion_send_output_report);
        } else {
                ret = 0;
        }
@@ -2421,6 +2434,56 @@ static void sony_remove(struct hid_device *hdev)
        hid_hw_stop(hdev);
 }
 
+#ifdef CONFIG_PM
+
+static int sony_suspend(struct hid_device *hdev, pm_message_t message)
+{
+       /*
+        * On suspend save the current LED state,
+        * stop running force-feedback and blank the LEDS.
+         */
+       if (SONY_LED_SUPPORT || SONY_FF_SUPPORT) {
+               struct sony_sc *sc = hid_get_drvdata(hdev);
+
+#ifdef CONFIG_SONY_FF
+               sc->left = sc->right = 0;
+#endif
+
+               memcpy(sc->resume_led_state, sc->led_state,
+                       sizeof(sc->resume_led_state));
+               memset(sc->led_state, 0, sizeof(sc->led_state));
+
+               sony_send_output_report(sc);
+       }
+
+       return 0;
+}
+
+static int sony_resume(struct hid_device *hdev)
+{
+       /* Restore the state of controller LEDs on resume */
+       if (SONY_LED_SUPPORT) {
+               struct sony_sc *sc = hid_get_drvdata(hdev);
+
+               memcpy(sc->led_state, sc->resume_led_state,
+                       sizeof(sc->led_state));
+
+               /*
+                * The Sixaxis and navigation controllers on USB need to be
+                * reinitialized on resume or they won't behave properly.
+                */
+               if ((sc->quirks & SIXAXIS_CONTROLLER_USB) ||
+                       (sc->quirks & NAVIGATION_CONTROLLER_USB))
+                       sixaxis_set_operational_usb(sc->hdev);
+
+               sony_set_leds(sc);
+       }
+
+       return 0;
+}
+
+#endif
+
 static const struct hid_device_id sony_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
                .driver_data = SIXAXIS_CONTROLLER_USB },
@@ -2470,7 +2533,13 @@ static struct hid_driver sony_driver = {
        .probe            = sony_probe,
        .remove           = sony_remove,
        .report_fixup     = sony_report_fixup,
-       .raw_event        = sony_raw_event
+       .raw_event        = sony_raw_event,
+
+#ifdef CONFIG_PM
+       .suspend          = sony_suspend,
+       .resume           = sony_resume,
+       .reset_resume     = sony_resume,
+#endif
 };
 
 static int __init sony_init(void)
index 3edd4ac..ec18768 100644 (file)
@@ -141,7 +141,7 @@ static void steelseries_srws1_led_all_set_brightness(struct led_classdev *led_cd
                        enum led_brightness value)
 {
        struct device *dev = led_cdev->dev->parent;
-       struct hid_device *hid = container_of(dev, struct hid_device, dev);
+       struct hid_device *hid = to_hid_device(dev);
        struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid);
 
        if (!drv_data) {
@@ -160,7 +160,7 @@ static void steelseries_srws1_led_all_set_brightness(struct led_classdev *led_cd
 static enum led_brightness steelseries_srws1_led_all_get_brightness(struct led_classdev *led_cdev)
 {
        struct device *dev = led_cdev->dev->parent;
-       struct hid_device *hid = container_of(dev, struct hid_device, dev);
+       struct hid_device *hid = to_hid_device(dev);
        struct steelseries_srws1_data *drv_data;
 
        drv_data = hid_get_drvdata(hid);
@@ -177,7 +177,7 @@ static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev,
                        enum led_brightness value)
 {
        struct device *dev = led_cdev->dev->parent;
-       struct hid_device *hid = container_of(dev, struct hid_device, dev);
+       struct hid_device *hid = to_hid_device(dev);
        struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid);
        int i, state = 0;
 
@@ -205,7 +205,7 @@ static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev,
 static enum led_brightness steelseries_srws1_led_get_brightness(struct led_classdev *led_cdev)
 {
        struct device *dev = led_cdev->dev->parent;
-       struct hid_device *hid = container_of(dev, struct hid_device, dev);
+       struct hid_device *hid = to_hid_device(dev);
        struct steelseries_srws1_data *drv_data;
        int i, value = 0;
 
index 05e23c4..4390eee 100644 (file)
@@ -296,14 +296,12 @@ static const struct wiimod_ops wiimod_battery = {
 
 static enum led_brightness wiimod_led_get(struct led_classdev *led_dev)
 {
-       struct wiimote_data *wdata;
        struct device *dev = led_dev->dev->parent;
+       struct wiimote_data *wdata = dev_to_wii(dev);
        int i;
        unsigned long flags;
        bool value = false;
 
-       wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
-
        for (i = 0; i < 4; ++i) {
                if (wdata->leds[i] == led_dev) {
                        spin_lock_irqsave(&wdata->state.lock, flags);
@@ -319,14 +317,12 @@ static enum led_brightness wiimod_led_get(struct led_classdev *led_dev)
 static void wiimod_led_set(struct led_classdev *led_dev,
                           enum led_brightness value)
 {
-       struct wiimote_data *wdata;
        struct device *dev = led_dev->dev->parent;
+       struct wiimote_data *wdata = dev_to_wii(dev);
        int i;
        unsigned long flags;
        __u8 state, flag;
 
-       wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
-
        for (i = 0; i < 4; ++i) {
                if (wdata->leds[i] == led_dev) {
                        flag = WIIPROTO_FLAG_LED(i + 1);
index 875694d..510ca77 100644 (file)
@@ -256,8 +256,7 @@ enum wiiproto_reqs {
        WIIPROTO_REQ_MAX
 };
 
-#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \
-                                                                       dev))
+#define dev_to_wii(pdev) hid_get_drvdata(to_hid_device(pdev))
 
 void __wiimote_schedule(struct wiimote_data *wdata);
 
index 10bd8e6..b921693 100644 (file)
@@ -151,6 +151,7 @@ struct i2c_hid {
        struct i2c_hid_platform_data pdata;
 
        bool                    irq_wake_enabled;
+       struct mutex            reset_lock;
 };
 
 static int __i2c_hid_command(struct i2c_client *client,
@@ -356,9 +357,16 @@ static int i2c_hid_hwreset(struct i2c_client *client)
 
        i2c_hid_dbg(ihid, "%s\n", __func__);
 
+       /*
+        * This prevents sending feature reports while the device is
+        * being reset. Otherwise we may lose the reset complete
+        * interrupt.
+        */
+       mutex_lock(&ihid->reset_lock);
+
        ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
        if (ret)
-               return ret;
+               goto out_unlock;
 
        i2c_hid_dbg(ihid, "resetting...\n");
 
@@ -366,10 +374,11 @@ static int i2c_hid_hwreset(struct i2c_client *client)
        if (ret) {
                dev_err(&client->dev, "failed to reset device.\n");
                i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
-               return ret;
        }
 
-       return 0;
+out_unlock:
+       mutex_unlock(&ihid->reset_lock);
+       return ret;
 }
 
 static void i2c_hid_get_input(struct i2c_hid *ihid)
@@ -587,12 +596,15 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
                size_t count, unsigned char report_type, bool use_data)
 {
        struct i2c_client *client = hid->driver_data;
+       struct i2c_hid *ihid = i2c_get_clientdata(client);
        int report_id = buf[0];
        int ret;
 
        if (report_type == HID_INPUT_REPORT)
                return -EINVAL;
 
+       mutex_lock(&ihid->reset_lock);
+
        if (report_id) {
                buf++;
                count--;
@@ -605,6 +617,8 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
        if (report_id && ret >= 0)
                ret++; /* add report_id to the number of transfered bytes */
 
+       mutex_unlock(&ihid->reset_lock);
+
        return ret;
 }
 
@@ -990,6 +1004,7 @@ static int i2c_hid_probe(struct i2c_client *client,
        ihid->wHIDDescRegister = cpu_to_le16(hidRegister);
 
        init_waitqueue_head(&ihid->wait);
+       mutex_init(&ihid->reset_lock);
 
        /* we need to allocate the command buffer without knowing the maximum
         * size of the reports. Let's use HID_MIN_BUFFER_SIZE, then we do the
@@ -1184,7 +1199,6 @@ MODULE_DEVICE_TABLE(i2c, i2c_hid_id_table);
 static struct i2c_driver i2c_hid_driver = {
        .driver = {
                .name   = "i2c_hid",
-               .owner  = THIS_MODULE,
                .pm     = &i2c_hid_pm,
                .acpi_match_table = ACPI_PTR(i2c_hid_acpi_match),
                .of_match_table = of_match_ptr(i2c_hid_of_match),
index 36712e9..ad71160 100644 (file)
@@ -274,10 +274,10 @@ static void hid_irq_in(struct urb *urb)
 
        switch (urb->status) {
        case 0:                 /* success */
-               usbhid_mark_busy(usbhid);
                usbhid->retry_delay = 0;
                if ((hid->quirks & HID_QUIRK_ALWAYS_POLL) && !hid->open)
                        break;
+               usbhid_mark_busy(usbhid);
                if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
                        hid_input_report(urb->context, HID_INPUT_REPORT,
                                         urb->transfer_buffer,
@@ -477,8 +477,6 @@ static void hid_ctrl(struct urb *urb)
        struct usbhid_device *usbhid = hid->driver_data;
        int unplug = 0, status = urb->status;
 
-       spin_lock(&usbhid->lock);
-
        switch (status) {
        case 0:                 /* success */
                if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
@@ -498,6 +496,8 @@ static void hid_ctrl(struct urb *urb)
                hid_warn(urb->dev, "ctrl urb status %d received\n", status);
        }
 
+       spin_lock(&usbhid->lock);
+
        if (unplug) {
                usbhid->ctrltail = usbhid->ctrlhead;
        } else {
index e06af5b..5cb21dd 100644 (file)
@@ -686,7 +686,7 @@ out:
 static ssize_t wacom_led_select_store(struct device *dev, int set_id,
                                      const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct wacom *wacom = hid_get_drvdata(hdev);
        unsigned int id;
        int err;
@@ -714,7 +714,7 @@ static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \
 static ssize_t wacom_led##SET_ID##_select_show(struct device *dev,     \
        struct device_attribute *attr, char *buf)                       \
 {                                                                      \
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
+       struct hid_device *hdev = to_hid_device(dev);\
        struct wacom *wacom = hid_get_drvdata(hdev);                    \
        return scnprintf(buf, PAGE_SIZE, "%d\n",                        \
                         wacom->led.select[SET_ID]);                    \
@@ -750,7 +750,7 @@ static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
 static ssize_t wacom_##name##_luminance_store(struct device *dev,      \
        struct device_attribute *attr, const char *buf, size_t count)   \
 {                                                                      \
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
+       struct hid_device *hdev = to_hid_device(dev);\
        struct wacom *wacom = hid_get_drvdata(hdev);                    \
                                                                        \
        return wacom_luminance_store(wacom, &wacom->led.field,          \
@@ -773,7 +773,7 @@ DEVICE_LUMINANCE_ATTR(buttons, img_lum);
 static ssize_t wacom_button_image_store(struct device *dev, int button_id,
                                        const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct wacom *wacom = hid_get_drvdata(hdev);
        int err;
        unsigned len;
@@ -1097,7 +1097,7 @@ static ssize_t wacom_show_speed(struct device *dev,
                                struct device_attribute
                                *attr, char *buf)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct wacom *wacom = hid_get_drvdata(hdev);
 
        return snprintf(buf, PAGE_SIZE, "%i\n", wacom->wacom_wac.bt_high_speed);
@@ -1107,7 +1107,7 @@ static ssize_t wacom_store_speed(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t count)
 {
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct hid_device *hdev = to_hid_device(dev);
        struct wacom *wacom = hid_get_drvdata(hdev);
        u8 new_speed;
 
@@ -1130,8 +1130,8 @@ static ssize_t wacom_show_remote_mode(struct kobject *kobj,
                                      struct kobj_attribute *kattr,
                                      char *buf, int index)
 {
-       struct device *dev = container_of(kobj->parent, struct device, kobj);
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct device *dev = kobj_to_dev(kobj->parent);
+       struct hid_device *hdev = to_hid_device(dev);
        struct wacom *wacom = hid_get_drvdata(hdev);
        u8 mode;
 
@@ -1241,8 +1241,8 @@ static ssize_t wacom_store_unpair_remote(struct kobject *kobj,
                                         const char *buf, size_t count)
 {
        unsigned char selector = 0;
-       struct device *dev = container_of(kobj->parent, struct device, kobj);
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct device *dev = kobj_to_dev(kobj->parent);
+       struct hid_device *hdev = to_hid_device(dev);
        struct wacom *wacom = hid_get_drvdata(hdev);
        int err;
 
@@ -1353,8 +1353,7 @@ static void wacom_clean_inputs(struct wacom *wacom)
                else
                        input_free_device(wacom->wacom_wac.pad_input);
        }
-       if (wacom->remote_dir)
-               kobject_put(wacom->remote_dir);
+       kobject_put(wacom->remote_dir);
        wacom->wacom_wac.pen_input = NULL;
        wacom->wacom_wac.touch_input = NULL;
        wacom->wacom_wac.pad_input = NULL;
index 01a4f05..99ef77f 100644 (file)
@@ -34,6 +34,9 @@
  */
 #define WACOM_CONTACT_AREA_SCALE 2607
 
+static void wacom_report_numbered_buttons(struct input_dev *input_dev,
+                               int button_count, int mask);
+
 /*
  * Percent of battery capacity for Graphire.
  * 8th value means AC online and show 100% capacity.
@@ -436,16 +439,142 @@ exit:
 static void wacom_intuos_schedule_prox_event(struct wacom_wac *wacom_wac)
 {
        struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+       struct wacom_features *features = &wacom_wac->features;
        struct hid_report *r;
        struct hid_report_enum *re;
 
        re = &(wacom->hdev->report_enum[HID_FEATURE_REPORT]);
-       r = re->report_id_hash[WACOM_REPORT_INTUOSREAD];
+       if (features->type == INTUOSHT2)
+               r = re->report_id_hash[WACOM_REPORT_INTUOSHT2_ID];
+       else
+               r = re->report_id_hash[WACOM_REPORT_INTUOS_ID1];
        if (r) {
                hid_hw_request(wacom->hdev, r, HID_REQ_GET_REPORT);
        }
 }
 
+static int wacom_intuos_pad(struct wacom_wac *wacom)
+{
+       struct wacom_features *features = &wacom->features;
+       unsigned char *data = wacom->data;
+       struct input_dev *input = wacom->pad_input;
+       int i;
+       int buttons = 0, nbuttons = features->numbered_buttons;
+       int keys = 0, nkeys = 0;
+       int ring1 = 0, ring2 = 0;
+       int strip1 = 0, strip2 = 0;
+       bool prox = false;
+
+       /* pad packets. Works as a second tool and is always in prox */
+       if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
+             data[0] == WACOM_REPORT_CINTIQPAD))
+               return 0;
+
+       if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
+               buttons = (data[3] << 1) | (data[2] & 0x01);
+               ring1 = data[1];
+       } else if (features->type == DTK) {
+               buttons = data[6];
+       } else if (features->type == WACOM_13HD) {
+               buttons = (data[4] << 1) | (data[3] & 0x01);
+       } else if (features->type == WACOM_24HD) {
+               buttons = (data[8] << 8) | data[6];
+               ring1 = data[1];
+               ring2 = data[2];
+
+               /*
+                * Three "buttons" are available on the 24HD which are
+                * physically implemented as a touchstrip. Each button
+                * is approximately 3 bits wide with a 2 bit spacing.
+                * The raw touchstrip bits are stored at:
+                *    ((data[3] & 0x1f) << 8) | data[4])
+                */
+               nkeys = 3;
+               keys = ((data[3] & 0x1C) ? 1<<2 : 0) |
+                      ((data[4] & 0xE0) ? 1<<1 : 0) |
+                      ((data[4] & 0x07) ? 1<<0 : 0);
+       } else if (features->type == WACOM_27QHD) {
+               nkeys = 3;
+               keys = data[2] & 0x07;
+
+               input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
+               input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
+               input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
+       } else if (features->type == CINTIQ_HYBRID) {
+               /*
+                * Do not send hardware buttons under Android. They
+                * are already sent to the system through GPIO (and
+                * have different meaning).
+                *
+                * d-pad right  -> data[4] & 0x10
+                * d-pad up     -> data[4] & 0x20
+                * d-pad left   -> data[4] & 0x40
+                * d-pad down   -> data[4] & 0x80
+                * d-pad center -> data[3] & 0x01
+                */
+               buttons = (data[4] << 1) | (data[3] & 0x01);
+       } else if (features->type == CINTIQ_COMPANION_2) {
+               /* d-pad right  -> data[4] & 0x10
+                * d-pad up     -> data[4] & 0x20
+                * d-pad left   -> data[4] & 0x40
+                * d-pad down   -> data[4] & 0x80
+                * d-pad center -> data[3] & 0x01
+                */
+               buttons = ((data[2] >> 4) << 7) |
+                         ((data[1] & 0x04) << 6) |
+                         ((data[2] & 0x0F) << 2) |
+                         (data[1] & 0x03);
+       } else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
+               /*
+                * ExpressKeys on Intuos5/Intuos Pro have a capacitive sensor in
+                * addition to the mechanical switch. Switch data is
+                * stored in data[4], capacitive data in data[5].
+                *
+                * Touch ring mode switch (data[3]) has no capacitive sensor
+                */
+               buttons = (data[4] << 1) | (data[3] & 0x01);
+               ring1 = data[2];
+       } else {
+               if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
+                       buttons = (data[8] << 10) | ((data[7] & 0x01) << 9) |
+                                 (data[6] << 1) | (data[5] & 0x01);
+
+                       if (features->type == WACOM_22HD) {
+                               nkeys = 3;
+                               keys = data[9] & 0x07;
+                       }
+               } else {
+                       buttons = ((data[6] & 0x10) << 10) |
+                                 ((data[5] & 0x10) << 9)  |
+                                 ((data[6] & 0x0F) << 4)  |
+                                 (data[5] & 0x0F);
+               }
+               strip1 = ((data[1] & 0x1f) << 8) | data[2];
+               strip2 = ((data[3] & 0x1f) << 8) | data[4];
+       }
+
+       prox = (buttons & ~(~0 << nbuttons)) | (keys & ~(~0 << nkeys)) |
+              (ring1 & 0x80) | (ring2 & 0x80) | strip1 | strip2;
+
+       wacom_report_numbered_buttons(input, nbuttons, buttons);
+
+       for (i = 0; i < nkeys; i++)
+               input_report_key(input, KEY_PROG1 + i, keys & (1 << i));
+
+       input_report_abs(input, ABS_RX, strip1);
+       input_report_abs(input, ABS_RY, strip2);
+
+       input_report_abs(input, ABS_WHEEL,    (ring1 & 0x80) ? (ring1 & 0x7f) : 0);
+       input_report_abs(input, ABS_THROTTLE, (ring2 & 0x80) ? (ring2 & 0x7f) : 0);
+
+       input_report_key(input, wacom->tool[1], prox ? 1 : 0);
+       input_report_abs(input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
+
+       input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
+
+       return 1;
+}
+
 static int wacom_intuos_inout(struct wacom_wac *wacom)
 {
        struct wacom_features *features = &wacom->features;
@@ -755,19 +884,40 @@ static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
        return 0;
 }
 
-static void wacom_intuos_general(struct wacom_wac *wacom)
+static int wacom_intuos_general(struct wacom_wac *wacom)
 {
        struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        struct input_dev *input = wacom->pen_input;
-       unsigned int t;
+       int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0;
+       unsigned char type = (data[1] >> 1) & 0x0F;
+       unsigned int x, y, distance, t;
 
-       /* general pen packet */
-       if ((data[1] & 0xb8) == 0xa0) {
-               t = (data[6] << 2) | ((data[7] >> 6) & 3);
-               if (features->pressure_max == 2047) {
-                       t = (t << 1) | (data[1] & 1);
-               }
+       if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_CINTIQ &&
+               data[0] != WACOM_REPORT_INTUOS_PEN)
+               return 0;
+
+       x = (be16_to_cpup((__be16 *)&data[2]) << 1) | ((data[9] >> 1) & 1);
+       y = (be16_to_cpup((__be16 *)&data[4]) << 1) | (data[9] & 1);
+       distance = data[9] >> 2;
+       if (features->type < INTUOS3S) {
+               x >>= 1;
+               y >>= 1;
+               distance >>= 1;
+       }
+       input_report_abs(input, ABS_X, x);
+       input_report_abs(input, ABS_Y, y);
+       input_report_abs(input, ABS_DISTANCE, distance);
+
+       switch (type) {
+       case 0x00:
+       case 0x01:
+       case 0x02:
+       case 0x03:
+               /* general pen packet */
+               t = (data[6] << 3) | ((data[7] & 0xC0) >> 5) | (data[1] & 1);
+               if (features->pressure_max < 2047)
+                       t >>= 1;
                input_report_abs(input, ABS_PRESSURE, t);
                if (features->type != INTUOSHT2) {
                    input_report_abs(input, ABS_TILT_X,
@@ -777,29 +927,112 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
                input_report_key(input, BTN_STYLUS, data[1] & 2);
                input_report_key(input, BTN_STYLUS2, data[1] & 4);
                input_report_key(input, BTN_TOUCH, t > 10);
-       }
+               break;
 
-       /* airbrush second packet */
-       if ((data[1] & 0xbc) == 0xb4) {
+       case 0x0a:
+               /* airbrush second packet */
                input_report_abs(input, ABS_WHEEL,
                                (data[6] << 2) | ((data[7] >> 6) & 3));
                input_report_abs(input, ABS_TILT_X,
                                 (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
                input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
+               break;
+
+       case 0x05:
+               /* Rotation packet */
+               if (features->type >= INTUOS3S) {
+                       /* I3 marker pen rotation */
+                       t = (data[6] << 3) | ((data[7] >> 5) & 7);
+                       t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+                               ((t-1) / 2 + 450)) : (450 - t / 2) ;
+                       input_report_abs(input, ABS_Z, t);
+               } else {
+                       /* 4D mouse 2nd packet */
+                       t = (data[6] << 3) | ((data[7] >> 5) & 7);
+                       input_report_abs(input, ABS_RZ, (data[7] & 0x20) ?
+                               ((t - 1) / 2) : -t / 2);
+               }
+               break;
+
+       case 0x04:
+               /* 4D mouse 1st packet */
+               input_report_key(input, BTN_LEFT,   data[8] & 0x01);
+               input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
+               input_report_key(input, BTN_RIGHT,  data[8] & 0x04);
+
+               input_report_key(input, BTN_SIDE,   data[8] & 0x20);
+               input_report_key(input, BTN_EXTRA,  data[8] & 0x10);
+               t = (data[6] << 2) | ((data[7] >> 6) & 3);
+               input_report_abs(input, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
+               break;
+
+       case 0x06:
+               /* I4 mouse */
+               input_report_key(input, BTN_LEFT,   data[6] & 0x01);
+               input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
+               input_report_key(input, BTN_RIGHT,  data[6] & 0x04);
+               input_report_rel(input, REL_WHEEL, ((data[7] & 0x80) >> 7)
+                                - ((data[7] & 0x40) >> 6));
+               input_report_key(input, BTN_SIDE,   data[6] & 0x08);
+               input_report_key(input, BTN_EXTRA,  data[6] & 0x10);
+
+               input_report_abs(input, ABS_TILT_X,
+                       (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
+               input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
+               break;
+
+       case 0x08:
+               if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
+                       /* 2D mouse packet */
+                       input_report_key(input, BTN_LEFT,   data[8] & 0x04);
+                       input_report_key(input, BTN_MIDDLE, data[8] & 0x08);
+                       input_report_key(input, BTN_RIGHT,  data[8] & 0x10);
+                       input_report_rel(input, REL_WHEEL, (data[8] & 0x01)
+                                        - ((data[8] & 0x02) >> 1));
+
+                       /* I3 2D mouse side buttons */
+                       if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
+                               input_report_key(input, BTN_SIDE,   data[8] & 0x40);
+                               input_report_key(input, BTN_EXTRA,  data[8] & 0x20);
+                       }
+               }
+               else if (wacom->tool[idx] == BTN_TOOL_LENS) {
+                       /* Lens cursor packets */
+                       input_report_key(input, BTN_LEFT,   data[8] & 0x01);
+                       input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
+                       input_report_key(input, BTN_RIGHT,  data[8] & 0x04);
+                       input_report_key(input, BTN_SIDE,   data[8] & 0x10);
+                       input_report_key(input, BTN_EXTRA,  data[8] & 0x08);
+               }
+               break;
+
+       case 0x07:
+       case 0x09:
+       case 0x0b:
+       case 0x0c:
+       case 0x0d:
+       case 0x0e:
+       case 0x0f:
+               /* unhandled */
+               break;
        }
+
+       input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */
+       input_report_key(input, wacom->tool[idx], 1);
+       input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+       wacom->reporting_data = true;
+       return 2;
 }
 
 static int wacom_intuos_irq(struct wacom_wac *wacom)
 {
-       struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        struct input_dev *input = wacom->pen_input;
-       unsigned int t;
-       int idx = 0, result;
+       int result;
 
        if (data[0] != WACOM_REPORT_PENABLED &&
-           data[0] != WACOM_REPORT_INTUOSREAD &&
-           data[0] != WACOM_REPORT_INTUOSWRITE &&
+           data[0] != WACOM_REPORT_INTUOS_ID1 &&
+           data[0] != WACOM_REPORT_INTUOS_ID2 &&
            data[0] != WACOM_REPORT_INTUOSPAD &&
            data[0] != WACOM_REPORT_INTUOS_PEN &&
            data[0] != WACOM_REPORT_CINTIQ &&
@@ -810,339 +1043,22 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                 return 0;
        }
 
-       /* tool number */
-       if (features->type == INTUOS)
-               idx = data[1] & 0x01;
-
-       /* pad packets. Works as a second tool and is always in prox */
-       if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
-           data[0] == WACOM_REPORT_CINTIQPAD) {
-               input = wacom->pad_input;
-               if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
-                       input_report_key(input, BTN_0, (data[2] & 0x01));
-                       input_report_key(input, BTN_1, (data[3] & 0x01));
-                       input_report_key(input, BTN_2, (data[3] & 0x02));
-                       input_report_key(input, BTN_3, (data[3] & 0x04));
-                       input_report_key(input, BTN_4, (data[3] & 0x08));
-                       input_report_key(input, BTN_5, (data[3] & 0x10));
-                       input_report_key(input, BTN_6, (data[3] & 0x20));
-                       if (data[1] & 0x80) {
-                               input_report_abs(input, ABS_WHEEL, (data[1] & 0x7f));
-                       } else {
-                               /* Out of proximity, clear wheel value. */
-                               input_report_abs(input, ABS_WHEEL, 0);
-                       }
-                       if (features->type != INTUOS4S) {
-                               input_report_key(input, BTN_7, (data[3] & 0x40));
-                               input_report_key(input, BTN_8, (data[3] & 0x80));
-                       }
-                       if (data[1] | (data[2] & 0x01) | data[3]) {
-                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-                       } else {
-                               input_report_abs(input, ABS_MISC, 0);
-                       }
-               } else if (features->type == DTK) {
-                       input_report_key(input, BTN_0, (data[6] & 0x01));
-                       input_report_key(input, BTN_1, (data[6] & 0x02));
-                       input_report_key(input, BTN_2, (data[6] & 0x04));
-                       input_report_key(input, BTN_3, (data[6] & 0x08));
-                       input_report_key(input, BTN_4, (data[6] & 0x10));
-                       input_report_key(input, BTN_5, (data[6] & 0x20));
-                       if (data[6] & 0x3f) {
-                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-                       } else {
-                               input_report_abs(input, ABS_MISC, 0);
-                       }
-               } else if (features->type == WACOM_13HD) {
-                       input_report_key(input, BTN_0, (data[3] & 0x01));
-                       input_report_key(input, BTN_1, (data[4] & 0x01));
-                       input_report_key(input, BTN_2, (data[4] & 0x02));
-                       input_report_key(input, BTN_3, (data[4] & 0x04));
-                       input_report_key(input, BTN_4, (data[4] & 0x08));
-                       input_report_key(input, BTN_5, (data[4] & 0x10));
-                       input_report_key(input, BTN_6, (data[4] & 0x20));
-                       input_report_key(input, BTN_7, (data[4] & 0x40));
-                       input_report_key(input, BTN_8, (data[4] & 0x80));
-                       if ((data[3] & 0x01) | data[4]) {
-                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-                       } else {
-                               input_report_abs(input, ABS_MISC, 0);
-                       }
-               } else if (features->type == WACOM_24HD) {
-                       input_report_key(input, BTN_0, (data[6] & 0x01));
-                       input_report_key(input, BTN_1, (data[6] & 0x02));
-                       input_report_key(input, BTN_2, (data[6] & 0x04));
-                       input_report_key(input, BTN_3, (data[6] & 0x08));
-                       input_report_key(input, BTN_4, (data[6] & 0x10));
-                       input_report_key(input, BTN_5, (data[6] & 0x20));
-                       input_report_key(input, BTN_6, (data[6] & 0x40));
-                       input_report_key(input, BTN_7, (data[6] & 0x80));
-                       input_report_key(input, BTN_8, (data[8] & 0x01));
-                       input_report_key(input, BTN_9, (data[8] & 0x02));
-                       input_report_key(input, BTN_A, (data[8] & 0x04));
-                       input_report_key(input, BTN_B, (data[8] & 0x08));
-                       input_report_key(input, BTN_C, (data[8] & 0x10));
-                       input_report_key(input, BTN_X, (data[8] & 0x20));
-                       input_report_key(input, BTN_Y, (data[8] & 0x40));
-                       input_report_key(input, BTN_Z, (data[8] & 0x80));
-
-                       /*
-                        * Three "buttons" are available on the 24HD which are
-                        * physically implemented as a touchstrip. Each button
-                        * is approximately 3 bits wide with a 2 bit spacing.
-                        * The raw touchstrip bits are stored at:
-                        *    ((data[3] & 0x1f) << 8) | data[4])
-                        */
-                       input_report_key(input, KEY_PROG1, data[4] & 0x07);
-                       input_report_key(input, KEY_PROG2, data[4] & 0xE0);
-                       input_report_key(input, KEY_PROG3, data[3] & 0x1C);
-
-                       if (data[1] & 0x80) {
-                               input_report_abs(input, ABS_WHEEL, (data[1] & 0x7f));
-                       } else {
-                               /* Out of proximity, clear wheel value. */
-                               input_report_abs(input, ABS_WHEEL, 0);
-                       }
-
-                       if (data[2] & 0x80) {
-                               input_report_abs(input, ABS_THROTTLE, (data[2] & 0x7f));
-                       } else {
-                               /* Out of proximity, clear second wheel value. */
-                               input_report_abs(input, ABS_THROTTLE, 0);
-                       }
-
-                       if (data[1] | data[2] | (data[3] & 0x1f) | data[4] | data[6] | data[8]) {
-                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-                       } else {
-                               input_report_abs(input, ABS_MISC, 0);
-                       }
-               } else if (features->type == WACOM_27QHD) {
-                       input_report_key(input, KEY_PROG1, data[2] & 0x01);
-                       input_report_key(input, KEY_PROG2, data[2] & 0x02);
-                       input_report_key(input, KEY_PROG3, data[2] & 0x04);
-
-                       input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
-                       input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
-                       input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
-                       if ((data[2] & 0x07) | data[4] | data[5] | data[6] | data[7] | data[8] | data[9]) {
-                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-                       } else {
-                               input_report_abs(input, ABS_MISC, 0);
-                       }
-               } else if (features->type == CINTIQ_HYBRID) {
-                       /*
-                        * Do not send hardware buttons under Android. They
-                        * are already sent to the system through GPIO (and
-                        * have different meaning).
-                        */
-                       input_report_key(input, BTN_1, (data[4] & 0x01));
-                       input_report_key(input, BTN_2, (data[4] & 0x02));
-                       input_report_key(input, BTN_3, (data[4] & 0x04));
-                       input_report_key(input, BTN_4, (data[4] & 0x08));
-
-                       input_report_key(input, BTN_5, (data[4] & 0x10));  /* Right  */
-                       input_report_key(input, BTN_6, (data[4] & 0x20));  /* Up     */
-                       input_report_key(input, BTN_7, (data[4] & 0x40));  /* Left   */
-                       input_report_key(input, BTN_8, (data[4] & 0x80));  /* Down   */
-                       input_report_key(input, BTN_0, (data[3] & 0x01));  /* Center */
-
-                       if (data[4] | (data[3] & 0x01)) {
-                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-                       } else {
-                               input_report_abs(input, ABS_MISC, 0);
-                       }
-
-               } else if (features->type == CINTIQ_COMPANION_2) {
-                       input_report_key(input, BTN_1, (data[1] & 0x02));
-                       input_report_key(input, BTN_2, (data[2] & 0x01));
-                       input_report_key(input, BTN_3, (data[2] & 0x02));
-                       input_report_key(input, BTN_4, (data[2] & 0x04));
-                       input_report_key(input, BTN_5, (data[2] & 0x08));
-                       input_report_key(input, BTN_6, (data[1] & 0x04));
-
-                       input_report_key(input, BTN_7, (data[2] & 0x10));  /* Right  */
-                       input_report_key(input, BTN_8, (data[2] & 0x20));  /* Up         */
-                       input_report_key(input, BTN_9, (data[2] & 0x40));  /* Left   */
-                       input_report_key(input, BTN_A, (data[2] & 0x80));  /* Down   */
-                       input_report_key(input, BTN_0, (data[1] & 0x01));  /* Center */
-
-                       if (data[2] | (data[1] & 0x07)) {
-                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-                       } else {
-                               input_report_abs(input, ABS_MISC, 0);
-                       }
-
-               } else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
-                       int i;
-
-                       /* Touch ring mode switch has no capacitive sensor */
-                       input_report_key(input, BTN_0, (data[3] & 0x01));
-
-                       /*
-                        * ExpressKeys on Intuos5/Intuos Pro have a capacitive sensor in
-                        * addition to the mechanical switch. Switch data is
-                        * stored in data[4], capacitive data in data[5].
-                        */
-                       for (i = 0; i < 8; i++)
-                               input_report_key(input, BTN_1 + i, data[4] & (1 << i));
-
-                       if (data[2] & 0x80) {
-                               input_report_abs(input, ABS_WHEEL, (data[2] & 0x7f));
-                       } else {
-                               /* Out of proximity, clear wheel value. */
-                               input_report_abs(input, ABS_WHEEL, 0);
-                       }
-
-                       if (data[2] | (data[3] & 0x01) | data[4] | data[5]) {
-                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-                       } else {
-                               input_report_abs(input, ABS_MISC, 0);
-                       }
-               } else {
-                       if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
-                               input_report_key(input, BTN_0, (data[5] & 0x01));
-                               input_report_key(input, BTN_1, (data[6] & 0x01));
-                               input_report_key(input, BTN_2, (data[6] & 0x02));
-                               input_report_key(input, BTN_3, (data[6] & 0x04));
-                               input_report_key(input, BTN_4, (data[6] & 0x08));
-                               input_report_key(input, BTN_5, (data[6] & 0x10));
-                               input_report_key(input, BTN_6, (data[6] & 0x20));
-                               input_report_key(input, BTN_7, (data[6] & 0x40));
-                               input_report_key(input, BTN_8, (data[6] & 0x80));
-                               input_report_key(input, BTN_9, (data[7] & 0x01));
-                               input_report_key(input, BTN_A, (data[8] & 0x01));
-                               input_report_key(input, BTN_B, (data[8] & 0x02));
-                               input_report_key(input, BTN_C, (data[8] & 0x04));
-                               input_report_key(input, BTN_X, (data[8] & 0x08));
-                               input_report_key(input, BTN_Y, (data[8] & 0x10));
-                               input_report_key(input, BTN_Z, (data[8] & 0x20));
-                               input_report_key(input, BTN_BASE, (data[8] & 0x40));
-                               input_report_key(input, BTN_BASE2, (data[8] & 0x80));
-
-                               if (features->type == WACOM_22HD) {
-                                       input_report_key(input, KEY_PROG1, data[9] & 0x01);
-                                       input_report_key(input, KEY_PROG2, data[9] & 0x02);
-                                       input_report_key(input, KEY_PROG3, data[9] & 0x04);
-                               }
-                       } else {
-                               input_report_key(input, BTN_0, (data[5] & 0x01));
-                               input_report_key(input, BTN_1, (data[5] & 0x02));
-                               input_report_key(input, BTN_2, (data[5] & 0x04));
-                               input_report_key(input, BTN_3, (data[5] & 0x08));
-                               input_report_key(input, BTN_4, (data[6] & 0x01));
-                               input_report_key(input, BTN_5, (data[6] & 0x02));
-                               input_report_key(input, BTN_6, (data[6] & 0x04));
-                               input_report_key(input, BTN_7, (data[6] & 0x08));
-                               input_report_key(input, BTN_8, (data[5] & 0x10));
-                               input_report_key(input, BTN_9, (data[6] & 0x10));
-                       }
-                       input_report_abs(input, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
-                       input_report_abs(input, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
-
-                       if ((data[5] & 0x1f) | data[6] | (data[1] & 0x1f) |
-                               data[2] | (data[3] & 0x1f) | data[4] | data[8] |
-                               (data[7] & 0x01)) {
-                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-                       } else {
-                               input_report_abs(input, ABS_MISC, 0);
-                       }
-               }
-                return 1;
-       }
+       /* process pad events */
+       result = wacom_intuos_pad(wacom);
+       if (result)
+               return result;
 
        /* process in/out prox events */
        result = wacom_intuos_inout(wacom);
        if (result)
-                return result - 1;
-
-       if (features->type >= INTUOS3S) {
-               input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
-               input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
-               input_report_abs(input, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
-       } else {
-               input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[2]));
-               input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[4]));
-               input_report_abs(input, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
-       }
+               return result - 1;
 
        /* process general packets */
-       wacom_intuos_general(wacom);
-
-       /* 4D mouse, 2D mouse, marker pen rotation, tilt mouse, or Lens cursor packets */
-       if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0 || (data[1] & 0xbc) == 0xac) {
-
-               if (data[1] & 0x02) {
-                       /* Rotation packet */
-                       if (features->type >= INTUOS3S) {
-                               /* I3 marker pen rotation */
-                               t = (data[6] << 3) | ((data[7] >> 5) & 7);
-                               t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
-                                       ((t-1) / 2 + 450)) : (450 - t / 2) ;
-                               input_report_abs(input, ABS_Z, t);
-                       } else {
-                               /* 4D mouse rotation packet */
-                               t = (data[6] << 3) | ((data[7] >> 5) & 7);
-                               input_report_abs(input, ABS_RZ, (data[7] & 0x20) ?
-                                       ((t - 1) / 2) : -t / 2);
-                       }
-
-               } else if (!(data[1] & 0x10) && features->type < INTUOS3S) {
-                       /* 4D mouse packet */
-                       input_report_key(input, BTN_LEFT,   data[8] & 0x01);
-                       input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
-                       input_report_key(input, BTN_RIGHT,  data[8] & 0x04);
-
-                       input_report_key(input, BTN_SIDE,   data[8] & 0x20);
-                       input_report_key(input, BTN_EXTRA,  data[8] & 0x10);
-                       t = (data[6] << 2) | ((data[7] >> 6) & 3);
-                       input_report_abs(input, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
-
-               } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
-                       /* I4 mouse */
-                       if (features->type >= INTUOS4S && features->type <= INTUOSPL) {
-                               input_report_key(input, BTN_LEFT,   data[6] & 0x01);
-                               input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
-                               input_report_key(input, BTN_RIGHT,  data[6] & 0x04);
-                               input_report_rel(input, REL_WHEEL, ((data[7] & 0x80) >> 7)
-                                                - ((data[7] & 0x40) >> 6));
-                               input_report_key(input, BTN_SIDE,   data[6] & 0x08);
-                               input_report_key(input, BTN_EXTRA,  data[6] & 0x10);
-
-                               input_report_abs(input, ABS_TILT_X,
-                                       (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
-                               input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
-                       } else {
-                               /* 2D mouse packet */
-                               input_report_key(input, BTN_LEFT,   data[8] & 0x04);
-                               input_report_key(input, BTN_MIDDLE, data[8] & 0x08);
-                               input_report_key(input, BTN_RIGHT,  data[8] & 0x10);
-                               input_report_rel(input, REL_WHEEL, (data[8] & 0x01)
-                                                - ((data[8] & 0x02) >> 1));
-
-                               /* I3 2D mouse side buttons */
-                               if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
-                                       input_report_key(input, BTN_SIDE,   data[8] & 0x40);
-                                       input_report_key(input, BTN_EXTRA,  data[8] & 0x20);
-                               }
-                       }
-               } else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
-                               features->type == INTUOS4L || features->type == INTUOS5L ||
-                               features->type == INTUOSPL) &&
-                          wacom->tool[idx] == BTN_TOOL_LENS) {
-                       /* Lens cursor packets */
-                       input_report_key(input, BTN_LEFT,   data[8] & 0x01);
-                       input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
-                       input_report_key(input, BTN_RIGHT,  data[8] & 0x04);
-                       input_report_key(input, BTN_SIDE,   data[8] & 0x10);
-                       input_report_key(input, BTN_EXTRA,  data[8] & 0x08);
-               }
-       }
+       result = wacom_intuos_general(wacom);
+       if (result)
+               return result - 1;
 
-       input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */
-       input_report_key(input, wacom->tool[idx], 1);
-       input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
-       wacom->reporting_data = true;
-       return 1;
+       return 0;
 }
 
 static int int_dist(int x1, int y1, int x2, int y2)
@@ -2509,7 +2425,7 @@ void wacom_setup_device_quirks(struct wacom *wacom)
                features->quirks |= WACOM_QUIRK_BATTERY;
 
        /* quirk for bamboo touch with 2 low res touches */
-       if (features->type == BAMBOO_PT &&
+       if ((features->type == BAMBOO_PT || features->type == BAMBOO_TOUCH) &&
            features->pktlen == WACOM_PKGLEN_BBTOUCH) {
                features->x_max <<= 5;
                features->y_max <<= 5;
@@ -2806,6 +2722,19 @@ static void wacom_setup_numbered_buttons(struct input_dev *input_dev,
                __set_bit(BTN_BASE + (i-16), input_dev->keybit);
 }
 
+static void wacom_report_numbered_buttons(struct input_dev *input_dev,
+                               int button_count, int mask)
+{
+       int i;
+
+       for (i = 0; i < button_count && i < 10; i++)
+               input_report_key(input_dev, BTN_0 + i, mask & (1 << i));
+       for (i = 10; i < button_count && i < 16; i++)
+               input_report_key(input_dev, BTN_A + (i-10), mask & (1 << i));
+       for (i = 16; i < button_count && i < 18; i++)
+               input_report_key(input_dev, BTN_BASE + (i-16), mask & (1 << i));
+}
+
 int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
                                   struct wacom_wac *wacom_wac)
 {
index 877c24a..25baa7f 100644 (file)
@@ -47,8 +47,8 @@
 /* wacom data packet report IDs */
 #define WACOM_REPORT_PENABLED          2
 #define WACOM_REPORT_PENABLED_BT       3
-#define WACOM_REPORT_INTUOSREAD                5
-#define WACOM_REPORT_INTUOSWRITE       6
+#define WACOM_REPORT_INTUOS_ID1                5
+#define WACOM_REPORT_INTUOS_ID2                6
 #define WACOM_REPORT_INTUOSPAD         12
 #define WACOM_REPORT_INTUOS5PAD                3
 #define WACOM_REPORT_DTUSPAD           21
@@ -70,6 +70,7 @@
 #define WACOM_REPORT_DEVICE_LIST       16
 #define WACOM_REPORT_INTUOS_PEN                16
 #define WACOM_REPORT_REMOTE            17
+#define WACOM_REPORT_INTUOSHT2_ID      8
 
 /* device quirks */
 #define WACOM_QUIRK_BBTOUCH_LOWRES     0x0001
index 251a1d3..75b66ec 100644 (file)
@@ -168,6 +168,8 @@ struct hid_item {
 #define HID_UP_MSVENDOR                0xff000000
 #define HID_UP_CUSTOM          0x00ff0000
 #define HID_UP_LOGIVENDOR      0xffbc0000
+#define HID_UP_LOGIVENDOR2   0xff090000
+#define HID_UP_LOGIVENDOR3   0xff430000
 #define HID_UP_LNVENDOR                0xffa00000
 #define HID_UP_SENSOR          0x00200000
 
@@ -563,6 +565,9 @@ struct hid_device {                                                 /* device report descriptor */
        wait_queue_head_t debug_wait;
 };
 
+#define to_hid_device(pdev) \
+       container_of(pdev, struct hid_device, dev)
+
 static inline void *hid_get_drvdata(struct hid_device *hdev)
 {
        return dev_get_drvdata(&hdev->dev);
@@ -712,6 +717,9 @@ struct hid_driver {
        struct device_driver driver;
 };
 
+#define to_hid_driver(pdrv) \
+       container_of(pdrv, struct hid_driver, driver)
+
 /**
  * hid_ll_driver - low level driver callbacks
  * @start: called on probe to start the device