]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branches 'for-4.10/upstream-fixes', 'for-4.11/intel-ish', 'for-4.11/mayflash...
authorJiri Kosina <jkosina@suse.cz>
Mon, 20 Feb 2017 14:01:57 +0000 (15:01 +0100)
committerJiri Kosina <jkosina@suse.cz>
Mon, 20 Feb 2017 14:01:57 +0000 (15:01 +0100)
1  2  3  4  5  6  7 
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/intel-ish-hid/ipc/pci-ish.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/wacom.h
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c

diff --combined drivers/hid/hid-core.c
index 1f6d0c0003815d97d6fc4f59d1ae41ede88fb74c,cff060b56da9d6cb8cb138657cf4efca7debef61,54e98ff7090dab2b2e6a5e6674d7e6fe8c647585,0ab9b0eb56a9c0809c7c30bc6f3d3e5c656163d7,34fdfd77cf262551950a5438fe80b3701a10a1d5,3146e30dfc61255687d95150efea84670710a858,ea36b557d5eea87b27171937fe9bc05f680b15a8..538ff697a4cfe28bb27a8c1c7e87391c7d894415
        */
       
       #define DRIVER_DESC "HID core driver"
----- -#define DRIVER_LICENSE "GPL"
       
       int hid_debug = 0;
       module_param_named(debug, hid_debug, int, 0600);
@@@@@@@@ -724,13 -724,13 -724,13 -724,7 -724,13 -723,13 -724,13 +723,7 @@@@@@@@ static void hid_scan_collection(struct 
                hid->group = HID_GROUP_SENSOR_HUB;
       
        if (hid->vendor == USB_VENDOR_ID_MICROSOFT &&
--- ---     (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 ||
--- ---      hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 ||
--- ---      hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP ||
--- ---      hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4 ||
--- ---      hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2 ||
--- ---      hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP ||
--- ---      hid->product == USB_DEVICE_ID_MS_POWER_COVER) &&
+++ +++     hid->product == USB_DEVICE_ID_MS_POWER_COVER &&
            hid->group == HID_GROUP_MULTITOUCH)
                hid->group = HID_GROUP_GENERIC;
       
@@@@@@@@ -826,7 -826,7 -826,7 -820,7 -826,8 -825,7 -826,7 +819,8 @@@@@@@@ static int hid_scan_report(struct hid_d
                hid->group = HID_GROUP_WACOM;
                break;
        case USB_VENDOR_ID_SYNAPTICS:
---- --         if (hid->group == HID_GROUP_GENERIC)
++++ ++         if (hid->group == HID_GROUP_GENERIC ||
++++ ++             hid->group == HID_GROUP_MULTITOUCH_WIN_8)
                        if ((parser->scan_flags & HID_SCAN_FLAG_VENDOR_SPECIFIC)
                            && (parser->scan_flags & HID_SCAN_FLAG_GD_POINTER))
                                /*
@@@@@@@@ -1887,6 -1887,6 -1887,9 -1881,6 -1888,6 -1886,6 -1887,6 +1881,9 @@@@@@@@ static const struct hid_device_id hid_h
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
       #if IS_ENABLED(CONFIG_HID_MAYFLASH)
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3) },
++ ++++ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR) },
++ ++++ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1) },
++ ++++ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2) },
       #endif
        { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_WN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_FA) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) },
       #endif
 ++++++ { HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MELFAS_MT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) },
--- --- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) },
--- --- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) },
--- --- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) },
--- --- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4) },
--- --- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2) },
--- --- { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM6533) },
++++ ++ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) },
        { }
       };
       
@@@@@@@@ -2315,7 -2314,7 -2317,7 -2302,7 -2316,7 -2313,7 -2314,7 +2307,7 @@@@@@@@ __ATTRIBUTE_GROUPS(hid_dev)
       
       static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
       {
--- --- struct hid_device *hdev = to_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))
@@@@@@@@ -2497,7 -2496,6 -2499,6 -2484,6 -2498,6 -2495,6 -2496,7 +2489,7 @@@@@@@@ static const struct hid_device_id hid_i
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
 +++++  { HID_USB_DEVICE(USB_VENDOR_ID_PETZL, USB_DEVICE_ID_PETZL_HEADLAMP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
       #if IS_ENABLED(CONFIG_MOUSE_SYNAPTICS_USB)
@@@@@@@@ -2868,5 -2866,5 -2869,5 -2854,5 -2868,5 -2865,5 -2867,5 +2860,5 @@@@@@@@ module_exit(hid_exit)
       MODULE_AUTHOR("Andreas Gal");
       MODULE_AUTHOR("Vojtech Pavlik");
       MODULE_AUTHOR("Jiri Kosina");
----- -MODULE_LICENSE(DRIVER_LICENSE);
+++++ +MODULE_LICENSE("GPL");
       
diff --combined drivers/hid/hid-ids.h
index 8943a58c626d36f6ae626dd84c2795e8615f56c1,ec277b96eaa1b33461aa7702f38864598b910e59,23cb33c366634c0aca17d77a7583c7e77a1fccb1,fd4ba3a222e11bd567475a9f6bac2c58919058fb,e82dccc336de49b26baee73b1196ff2cb60d57b2,ec277b96eaa1b33461aa7702f38864598b910e59,f46f2c5117fae76a1c87105363e5c8db4c8673a3..86c95d30ac801f2895caef97a575955289d352a4
       #define USB_VENDOR_ID_ALPS_JP            0x044E
       #define HID_DEVICE_ID_ALPS_U1_DUAL       0x120B
       
 ++++++#define USB_VENDOR_ID_AMI                0x046b
 ++++++#define USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE        0xff10
 ++++++
       #define USB_VENDOR_ID_ANTON              0x1130
       #define USB_DEVICE_ID_ANTON_TOUCH_PAD    0x3101
       
       #define USB_VENDOR_ID_DRAGONRISE         0x0079
       #define USB_DEVICE_ID_DRAGONRISE_WIIU            0x1800
       #define USB_DEVICE_ID_DRAGONRISE_PS3             0x1801
 - - - #define USB_DEVICE_ID_DRAGONRISE_GAMECUBE        0x1843
 + + + #define USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR      0x1803
-   - -#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE        0x1843
++ ++++#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE1       0x1843
++ ++++#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE2       0x1844
       
       #define USB_VENDOR_ID_DWAV               0x0eef
       #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER     0x0001
       #define USB_VENDOR_ID_FLATFROG           0x25b5
       #define USB_DEVICE_ID_MULTITOUCH_3200    0x0002
       
 + + + #define USB_VENDOR_ID_FUTABA            0x0547
 + + + #define USB_DEVICE_ID_LED_DISPLAY       0x7000
 + + + 
       #define USB_VENDOR_ID_ESSENTIAL_REALITY  0x0d7f
       #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
       
       #define USB_DEVICE_ID_LENOVO_CUSBKBD     0x6047
       #define USB_DEVICE_ID_LENOVO_CBTKBD      0x6048
       #define USB_DEVICE_ID_LENOVO_TPPRODOCK   0x6067
++++ ++#define USB_DEVICE_ID_LENOVO_X1_COVER    0x6085
       
       #define USB_VENDOR_ID_LG         0x1fd2
       #define USB_DEVICE_ID_LG_MULTITOUCH      0x0064
 ++++++#define USB_DEVICE_ID_LG_MELFAS_MT       0x6007
       
       #define USB_VENDOR_ID_LOGITECH           0x046d
       #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
       #define USB_DEVICE_ID_MS_SURFACE_PRO_2   0x0799
       #define USB_DEVICE_ID_MS_TOUCH_COVER_2   0x07a7
       #define USB_DEVICE_ID_MS_TYPE_COVER_2    0x07a9
--- ---#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3    0x07dc
--- ---#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2  0x07e2
--- ---#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd
--- ---#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4 0x07e4
--- ---#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2 0x07e8
--- ---#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP 0x07e9
       #define USB_DEVICE_ID_MS_POWER_COVER     0x07da
       
       #define USB_VENDOR_ID_MOJO               0x8282
       #define USB_VENDOR_ID_PETALYNX           0x18b1
       #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE     0x0037
       
 +++++ #define USB_VENDOR_ID_PETZL              0x2122
 +++++ #define USB_DEVICE_ID_PETZL_HEADLAMP     0x1234
 +++++ 
       #define USB_VENDOR_ID_PHILIPS            0x0471
       #define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617
       
index 20d647d2dd2cbfa5fb57fbc85de236147cf448ab,393f2e3d4679b3f1816c8e3d6c0ea34123652f29,20d647d2dd2cbfa5fb57fbc85de236147cf448ab,20d647d2dd2cbfa5fb57fbc85de236147cf448ab,20d647d2dd2cbfa5fb57fbc85de236147cf448ab,d20da39c696ca8d5cf9c1dd88eacad16cf1b1c0f,20d647d2dd2cbfa5fb57fbc85de236147cf448ab..8df81dc845295962a2e3b04b16e65ff990162176
       #include <linux/sched.h>
       #include <linux/interrupt.h>
       #include <linux/workqueue.h>
----- -#include <linux/miscdevice.h>
       #define CREATE_TRACE_POINTS
       #include <trace/events/intel_ish.h>
       #include "ishtp-dev.h"
@@@@@@@@ -47,7 -47,8 -47,7 -47,7 -47,7 -46,7 -47,7 +46,8 @@@@@@@@ MODULE_DEVICE_TABLE(pci, ish_pci_tbl)
        *
        * Callback to direct log messages to Linux trace buffers
        */
- -----static void ish_event_tracer(struct ishtp_device *dev, char *format, ...)
+ +++++static __printf(2, 3)
+ +++++void ish_event_tracer(struct ishtp_device *dev, const char *format, ...)
       {
        if (trace_ishtp_dump_enabled()) {
                va_list args;
@@@@@@@@ -205,12 -206,15 -205,12 -205,12 -205,12 -204,12 -205,12 +205,15 @@@@@@@@ static void ish_remove(struct pci_dev *
       #ifdef CONFIG_PM
       static struct device *ish_resume_device;
       
+ +++++/* 50ms to get resume response */
+ +++++#define WAIT_FOR_RESUME_ACK_MS           50
+ +++++
       /**
        * ish_resume_handler() - Work function to complete resume
        * @work:        work struct
        *
        * The resume work function to complete resume function asynchronously.
- ----- * There are two types of platforms, one where ISH is not powered off,
+ +++++ * There are two resume paths, one where ISH is not powered off,
        * in that case a simple resume message is enough, others we need
        * a reset sequence.
        */
@@@@@@@@ -218,20 -222,31 -218,20 -218,20 -218,20 -217,20 -218,20 +221,31 @@@@@@@@ static void ish_resume_handler(struct w
       {
        struct pci_dev *pdev = to_pci_dev(ish_resume_device);
        struct ishtp_device *dev = pci_get_drvdata(pdev);
+ +++++ uint32_t fwsts;
        int ret;
       
- ----- ishtp_send_resume(dev);
+ +++++ /* Get ISH FW status */
+ +++++ fwsts = IPC_GET_ISH_FWSTS(dev->ops->get_fw_status(dev));
       
- ----- /* 50 ms to get resume response */
- ----- if (dev->resume_flag)
- -----         ret = wait_event_interruptible_timeout(dev->resume_wait,
- -----                                                !dev->resume_flag,
- -----                                                msecs_to_jiffies(50));
+ +++++ /*
+ +++++  * If currently, in ISH FW, sensor app is loaded or beyond that,
+ +++++  * it means ISH isn't powered off, in this case, send a resume message.
+ +++++  */
+ +++++ if (fwsts >= FWSTS_SENSOR_APP_LOADED) {
+ +++++         ishtp_send_resume(dev);
+ +++++
+ +++++         /* Waiting to get resume response */
+ +++++         if (dev->resume_flag)
+ +++++                 ret = wait_event_interruptible_timeout(dev->resume_wait,
+ +++++                         !dev->resume_flag,
+ +++++                         msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));
+ +++++ }
       
        /*
- -----  * If no resume response. This platform  is not S0ix compatible
- -----  * So on resume full reboot of ISH processor will happen, so
- -----  * need to go through init sequence again
+ +++++  * If in ISH FW, sensor app isn't loaded yet, or no resume response.
+ +++++  * That means this platform is not S0ix compatible, or something is
+ +++++  * wrong with ISH FW. So on resume, full reboot of ISH processor will
+ +++++  * happen, so need to go through init sequence again.
         */
        if (dev->resume_flag)
                ish_init(dev);
index 30a2977e26454f10fd72b855ec0b634aa868dcae,b3e01c82af0512dce7a68e6bde908d7e3afeaba8,54b641efd9394987cf15f5b60901b89448f3d72e,f3c59396b15a0925acc5c118a01775a61f49743a,e9d6cc7cdfc5c8019422d45914dc0363448bcb12,b3e01c82af0512dce7a68e6bde908d7e3afeaba8,e9d6cc7cdfc5c8019422d45914dc0363448bcb12..d6847a664446529831395a962aacab7cb49ab8f5
@@@@@@@@ -57,7 -57,6 -57,6 -57,6 -57,6 -57,6 -57,6 +57,7 @@@@@@@@ static const struct hid_blacklist 
        { USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_AKAI, USB_DEVICE_ID_AKAI_MPKMINI2, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX, HID_QUIRK_NO_INIT_REPORTS },
 ++++++ { USB_VENDOR_ID_AMI, USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3, HID_QUIRK_MULTI_INPUT },
 - - -  { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE, HID_QUIRK_MULTI_INPUT },
 + + +  { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR, HID_QUIRK_MULTI_INPUT },
-   - - { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE, HID_QUIRK_MULTI_INPUT },
++ ++++ { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_ELAN, HID_ANY_ID, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
 + + +  { USB_VENDOR_ID_FUTABA, USB_DEVICE_ID_LED_DISPLAY, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2, HID_QUIRK_NO_INIT_REPORTS },
--- --- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS },
--- --- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2, HID_QUIRK_NO_INIT_REPORTS },
--- --- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS },
--- --- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4, HID_QUIRK_NO_INIT_REPORTS },
--- --- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2, HID_QUIRK_NO_INIT_REPORTS },
--- --- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
@@@@@@@@ -297,7 -294,7 -296,7 -288,7 -296,7 -294,7 -296,7 +291,7 @@@@@@@@ static void usbhid_remove_all_dquirks(v
       
       }
       
--- ---/** 
+++ +++/**
        * usbhid_quirks_init: apply USB HID quirks specified at module load time
        */
       int usbhid_quirks_init(char **quirks_param)
@@@@@@@@ -361,7 -358,7 -360,7 -352,7 -360,7 -358,7 -360,7 +355,7 @@@@@@@@ static const struct hid_blacklist *usbh
       
        if (bl_entry != NULL)
                dbg_hid("Found squirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n",
--- ---                         bl_entry->quirks, bl_entry->idVendor, 
+++ +++                         bl_entry->quirks, bl_entry->idVendor,
                                bl_entry->idProduct);
        return bl_entry;
       }
diff --combined drivers/hid/wacom.h
index d303e413306df41a1e3f080d5bdd3c00efa75caf,d303e413306df41a1e3f080d5bdd3c00efa75caf,d303e413306df41a1e3f080d5bdd3c00efa75caf,d303e413306df41a1e3f080d5bdd3c00efa75caf,d303e413306df41a1e3f080d5bdd3c00efa75caf,020956c5ba7775eec220f2059056d7cc494162da,d0d7dc1572ca92ede297d28d7c85220476dc3151..38ee2125412f32c87db8fd5159e443cf0f7bffbf
       #define DRIVER_VERSION "v2.00"
       #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
       #define DRIVER_DESC "USB Wacom tablet driver"
----- -#define DRIVER_LICENSE "GPL"
       
       #define USB_VENDOR_ID_WACOM      0x056a
       #define USB_VENDOR_ID_LENOVO     0x17ef
@@@@@@@@ -166,7 -166,7 -166,7 -166,7 -166,7 -165,7 -166,9 +165,9 @@@@@@@@ struct wacom 
        struct work_struct wireless_work;
        struct work_struct battery_work;
        struct work_struct remote_work;
++++++  struct delayed_work init_work;
        struct wacom_remote *remote;
++++++  bool generic_has_leds;
        struct wacom_leds {
                struct wacom_group_leds *groups;
                unsigned int count;
@@@@@@@@ -218,4 -218,4 -218,4 -218,4 -218,4 -217,4 -220,6 +219,6 @@@@@@@@ enum led_brightness wacom_leds_brightne
       struct wacom_led *wacom_led_find(struct wacom *wacom, unsigned int group,
                                 unsigned int id);
       struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur);
++++++ int wacom_equivalent_usage(int usage);
++++++ int wacom_initialize_leds(struct wacom *wacom);
       #endif
diff --combined drivers/hid/wacom_sys.c
index 8aeca038cc7331244eeeb5dc0468b22ef66e7d44,b9779bcbd1403f00114f9565c543df79583baa38,b9779bcbd1403f00114f9565c543df79583baa38,b9779bcbd1403f00114f9565c543df79583baa38,b9779bcbd1403f00114f9565c543df79583baa38,57a9faf5683012905e75f8ce2a60088a3f3a47c9,3586acbdb467fa6c601f4afcf9d2224dbb4af7e4..be8f7e2a026f428f51200e395792dd715a612eeb
       #include <linux/input/mt.h>
       
       #define WAC_MSG_RETRIES          5
------ 
------ #define WAC_CMD_WL_LED_CONTROL   0x03
------ #define WAC_CMD_LED_CONTROL      0x20
------ #define WAC_CMD_ICON_START       0x21
------ #define WAC_CMD_ICON_XFER        0x23
------ #define WAC_CMD_ICON_BT_XFER     0x26
       #define WAC_CMD_RETRIES          10
------ #define WAC_CMD_DELETE_PAIRING   0x20
------ #define WAC_CMD_UNPAIR_ALL       0xFF
       
       #define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP)
       #define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP)
@@@@@@@@ -120,11 -120,11 -120,11 -120,11 -120,11 -120,11 -112,12 +112,12 @@@@@@@@ static void wacom_feature_mapping(struc
        struct wacom *wacom = hid_get_drvdata(hdev);
        struct wacom_features *features = &wacom->wacom_wac.features;
        struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
++++++  unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
        u8 *data;
        int ret;
        int n;
       
------  switch (usage->hid) {
++++++  switch (equivalent_usage) {
        case HID_DG_CONTACTMAX:
                /* leave touch_max as is if predefined */
                if (!features->touch_max) {
@@@@@@@@ -333,8 -333,8 -333,8 -333,8 -333,8 -333,8 -326,14 +326,14 @@@@@@@@ static void wacom_post_parse_hid(struc
        if (features->type == HID_GENERIC) {
                /* Any last-minute generic device setup */
                if (features->touch_max > 1) {
------                  input_mt_init_slots(wacom_wac->touch_input, wacom_wac->features.touch_max,
------                              INPUT_MT_DIRECT);
++++++                  if (features->device_type & WACOM_DEVICETYPE_DIRECT)
++++++                          input_mt_init_slots(wacom_wac->touch_input,
++++++                                              wacom_wac->features.touch_max,
++++++                                              INPUT_MT_DIRECT);
++++++                  else
++++++                          input_mt_init_slots(wacom_wac->touch_input,
++++++                                              wacom_wac->features.touch_max,
++++++                                              INPUT_MT_POINTER);
                }
        }
       }
@@@@@@@@ -497,11 -497,11 -497,11 -497,11 -497,11 -497,11 -496,11 +496,11 @@@@@@@@ static int wacom_bt_query_tablet_data(s
        * from the tablet, it is necessary to switch the tablet out of this
        * mode and into one which sends the full range of tablet data.
        */
------ static int wacom_query_tablet_data(struct hid_device *hdev,
------          struct wacom_features *features)
++++++ static int _wacom_query_tablet_data(struct wacom *wacom)
       {
------  struct wacom *wacom = hid_get_drvdata(hdev);
++++++  struct hid_device *hdev = wacom->hdev;
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
++++++  struct wacom_features *features = &wacom_wac->features;
       
        if (hdev->bus == BUS_BLUETOOTH)
                return wacom_bt_query_tablet_data(hdev, 1, features);
@@@@@@@@ -740,11 -740,6 -740,6 -740,6 -740,6 -740,6 -739,11 +739,11 @@@@@@@@ static int wacom_add_shared_data(struc
                return retval;
        }
       
 +++++  if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)
 +++++          wacom_wac->shared->touch = hdev;
 +++++  else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN)
 +++++          wacom_wac->shared->pen = hdev;
 +++++ 
       out:
        mutex_unlock(&wacom_udev_list_lock);
        return retval;
@@@@@@@@ -757,9 -752,9 -752,9 -752,9 -752,9 -752,9 -756,6 +756,6 @@@@@@@@ static int wacom_led_control(struct wac
        unsigned char report_id = WAC_CMD_LED_CONTROL;
        int buf_size = 9;
       
------  if (!hid_get_drvdata(wacom->hdev))
------          return -ENODEV;
------ 
        if (!wacom->led.groups)
                return -ENOTSUPP;
       
                report_id = WAC_CMD_WL_LED_CONTROL;
                buf_size = 13;
        }
++++++  else if (wacom->wacom_wac.features.type == INTUOSP2_BT) {
++++++          report_id = WAC_CMD_WL_INTUOSP2;
++++++          buf_size = 51;
++++++  }
        buf = kzalloc(buf_size, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
       
------  if (wacom->wacom_wac.features.type >= INTUOS5S &&
------      wacom->wacom_wac.features.type <= INTUOSPL) {
++++++  if (wacom->wacom_wac.features.type == HID_GENERIC) {
++++++          buf[0] = WAC_CMD_LED_CONTROL_GENERIC;
++++++          buf[1] = wacom->led.llv;
++++++          buf[2] = wacom->led.groups[0].select & 0x03;
++++++ 
++++++  } else if ((wacom->wacom_wac.features.type >= INTUOS5S &&
++++++      wacom->wacom_wac.features.type <= INTUOSPL)) {
                /*
                 * Touch Ring and crop mark LED luminance may take on
                 * one of four values:
                } else
                        buf[1] = led_bits;
        }
++++++  else if (wacom->wacom_wac.features.type == INTUOSP2_BT) {
++++++          buf[0] = report_id;
++++++          buf[4] = 100; // Power Connection LED (ORANGE)
++++++          buf[5] = 100; // BT Connection LED (BLUE)
++++++          buf[6] = 100; // Paper Mode (RED?)
++++++          buf[7] = 100; // Paper Mode (GREEN?)
++++++          buf[8] = 100; // Paper Mode (BLUE?)
++++++          buf[9] = wacom->led.llv;
++++++          buf[10] = wacom->led.groups[0].select & 0x03;
++++++  }
        else {
                int led = wacom->led.groups[0].select | 0x4;
       
@@@@@@@@ -1032,6 -1027,6 -1027,6 -1027,6 -1027,6 -1027,6 -1047,17 +1047,17 @@@@@@@@ static struct attribute_group intuos5_l
        .attrs = intuos5_led_attrs,
       };
       
++++++ static struct attribute *generic_led_attrs[] = {
++++++  &dev_attr_status0_luminance.attr,
++++++  &dev_attr_status_led0_select.attr,
++++++  NULL
++++++ };
++++++ 
++++++ static struct attribute_group generic_led_attr_group = {
++++++  .name = "wacom_led",
++++++  .attrs = generic_led_attrs,
++++++ };
++++++ 
       struct wacom_sysfs_group_devres {
        struct attribute_group *group;
        struct kobject *root;
@@@@@@@@ -1353,7 -1348,7 -1348,7 -1348,7 -1348,7 -1348,7 -1379,7 +1379,7 @@@@@@@@ static int wacom_leds_alloc_and_registe
        return 0;
       }
       
------ static int wacom_initialize_leds(struct wacom *wacom)
++++++ int wacom_initialize_leds(struct wacom *wacom)
       {
        int error;
       
       
        /* Initialize default values */
        switch (wacom->wacom_wac.features.type) {
++++++  case HID_GENERIC:
++++++          if (!wacom->generic_has_leds)
++++++                  return 0;
++++++          wacom->led.llv = 100;
++++++          wacom->led.max_llv = 100;
++++++ 
++++++          error = wacom_leds_alloc_and_register(wacom, 1, 4, false);
++++++          if (error) {
++++++                  hid_err(wacom->hdev,
++++++                          "cannot create leds err: %d\n", error);
++++++                  return error;
++++++          }
++++++ 
++++++          error = wacom_devm_sysfs_create_group(wacom,
++++++                                                &generic_led_attr_group);
++++++          break;
++++++ 
        case INTUOS4S:
        case INTUOS4:
        case INTUOS4WL:
                                                      &intuos5_led_attr_group);
                break;
       
++++++  case INTUOSP2_BT:
++++++          wacom->led.llv = 50;
++++++          wacom->led.max_llv = 100;
++++++          error = wacom_leds_alloc_and_register(wacom, 1, 4, false);
++++++          if (error) {
++++++                  hid_err(wacom->hdev,
++++++                          "cannot create leds err: %d\n", error);
++++++                  return error;
++++++          }
++++++          return 0;
++++++ 
        case REMOTE:
                wacom->led.llv = 255;
                wacom->led.max_llv = 255;
                        "cannot create sysfs group err: %d\n", error);
                return error;
        }
------  wacom_led_control(wacom);
       
        return 0;
       }
       
++++++ static void wacom_init_work(struct work_struct *work)
++++++ {
++++++  struct wacom *wacom = container_of(work, struct wacom, init_work.work);
++++++ 
++++++  _wacom_query_tablet_data(wacom);
++++++  wacom_led_control(wacom);
++++++ }
++++++ 
++++++ static void wacom_query_tablet_data(struct wacom *wacom)
++++++ {
++++++  schedule_delayed_work(&wacom->init_work, msecs_to_jiffies(1000));
++++++ }
++++++ 
       static enum power_supply_property wacom_battery_props[] = {
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_PRESENT,
@@@@@@@@ -2020,6 -2015,6 -2015,6 -2015,6 -2015,6 -2015,6 -2086,24 +2086,24 @@@@@@@@ static void wacom_release_resources(str
        wacom->wacom_wac.pad_input = NULL;
       }
       
++++++ static void wacom_set_shared_values(struct wacom_wac *wacom_wac)
++++++ {
++++++  if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) {
++++++          wacom_wac->shared->type = wacom_wac->features.type;
++++++          wacom_wac->shared->touch_input = wacom_wac->touch_input;
++++++  }
++++++ 
++++++  if (wacom_wac->has_mute_touch_switch)
++++++          wacom_wac->shared->has_mute_touch_switch = true;
++++++ 
++++++  if (wacom_wac->shared->has_mute_touch_switch &&
++++++      wacom_wac->shared->touch_input) {
++++++          set_bit(EV_SW, wacom_wac->shared->touch_input->evbit);
++++++          input_set_capability(wacom_wac->shared->touch_input, EV_SW,
++++++                               SW_MUTE_DEVICE);
++++++  }
++++++ }
++++++ 
       static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
       {
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
        if (error)
                goto fail;
       
 -----  error = wacom_add_shared_data(hdev);
 -----  if (error)
 -----          goto fail;
 ----- 
        /*
         * Bamboo Pad has a generic hid handling for the Pen, and we switch it
         * into debug mode for the touch part.
       
        wacom_update_name(wacom, wireless ? " (WL)" : "");
       
 -----  if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)
 -----          wacom_wac->shared->touch = hdev;
 -----  else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN)
 -----          wacom_wac->shared->pen = hdev;
 +++++  error = wacom_add_shared_data(hdev);
 +++++  if (error)
 +++++          goto fail;
       
        if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) &&
             (features->quirks & WACOM_QUIRK_BATTERY)) {
       
        if (!wireless) {
                /* Note that if query fails it is not a hard failure */
------          wacom_query_tablet_data(hdev, features);
++++++          wacom_query_tablet_data(wacom);
        }
       
        /* touch only Bamboo doesn't support pen */
        if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
                error = hid_hw_open(hdev);
       
------  if ((wacom_wac->features.type == INTUOSHT ||
------       wacom_wac->features.type == INTUOSHT2) &&
------      (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)) {
------          wacom_wac->shared->type = wacom_wac->features.type;
------          wacom_wac->shared->touch_input = wacom_wac->touch_input;
------  }
------ 
++++++  wacom_set_shared_values(wacom_wac);
        devres_close_group(&hdev->dev, wacom);
       
        return 0;
@@@@@@@@ -2450,6 -2450,6 -2450,6 -2450,6 -2450,6 -2450,6 -2528,7 +2528,7 @@@@@@@@ static int wacom_probe(struct hid_devic
        wacom->usbdev = dev;
        wacom->intf = intf;
        mutex_init(&wacom->lock);
++++++  INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work);
        INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
        INIT_WORK(&wacom->battery_work, wacom_battery_work);
        INIT_WORK(&wacom->remote_work, wacom_remote_work);
@@@@@@@@ -2491,12 -2491,12 -2491,12 -2491,12 -2491,12 -2491,12 -2570,17 +2570,17 @@@@@@@@ static void wacom_remove(struct hid_dev
       
        hid_hw_stop(hdev);
       
++++++  cancel_delayed_work_sync(&wacom->init_work);
        cancel_work_sync(&wacom->wireless_work);
        cancel_work_sync(&wacom->battery_work);
        cancel_work_sync(&wacom->remote_work);
        if (hdev->bus == BUS_BLUETOOTH)
                device_remove_file(&hdev->dev, &dev_attr_speed);
       
++++++  /* make sure we don't trigger the LEDs */
++++++  wacom_led_groups_release(wacom);
++++++  wacom_release_resources(wacom);
++++++ 
        hid_set_drvdata(hdev, NULL);
       }
       
       static int wacom_resume(struct hid_device *hdev)
       {
        struct wacom *wacom = hid_get_drvdata(hdev);
------  struct wacom_features *features = &wacom->wacom_wac.features;
       
        mutex_lock(&wacom->lock);
       
        /* switch to wacom mode first */
------  wacom_query_tablet_data(hdev, features);
++++++  _wacom_query_tablet_data(wacom);
        wacom_led_control(wacom);
       
        mutex_unlock(&wacom->lock);
@@@@@@@@ -2540,4 -2540,4 -2540,4 -2540,4 -2540,4 -2540,4 -2623,4 +2623,4 @@@@@@@@ module_hid_driver(wacom_driver)
       MODULE_VERSION(DRIVER_VERSION);
       MODULE_AUTHOR(DRIVER_AUTHOR);
       MODULE_DESCRIPTION(DRIVER_DESC);
----- -MODULE_LICENSE(DRIVER_LICENSE);
+++++ +MODULE_LICENSE("GPL");
diff --combined drivers/hid/wacom_wac.c
index 672145b0d8f584d8fce50a74e799b36319448cb4,b1a9a3ca6d564c72d3f445e663b196af87743ed1,b1a9a3ca6d564c72d3f445e663b196af87743ed1,b1a9a3ca6d564c72d3f445e663b196af87743ed1,b1a9a3ca6d564c72d3f445e663b196af87743ed1,b1a9a3ca6d564c72d3f445e663b196af87743ed1,1f3bdd16e15976478247c02b9fbc7bb901dc2192..4aa3de9f1163b30eb64b4304f285a4167aef0cf0
@@@@@@@@ -43,6 -43,6 -43,6 -43,6 -43,6 -43,6 -43,8 +43,8 @@@@@@@@ static void wacom_report_numbered_butto
       
       static int wacom_numbered_button_to_key(int n);
       
++++++ static void wacom_update_led(struct wacom *wacom, int button_count, int mask,
++++++                       int group);
       /*
        * Percent of battery capacity for Graphire.
        * 8th value means AC online and show 100% capacity.
@@@@@@@@ -166,21 -166,19 -166,19 -166,19 -166,19 -166,19 -168,19 +168,21 @@@@@@@@ static int wacom_pl_irq(struct wacom_wa
                wacom->id[0] = STYLUS_DEVICE_ID;
        }
       
 ------ pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
 ------ if (features->pressure_max > 255)
 ------         pressure = (pressure << 1) | ((data[4] >> 6) & 1);
 ------ pressure += (features->pressure_max + 1) / 2;
      -
      - input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
      - input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
      - input_report_abs(input, ABS_PRESSURE, pressure);
      -
      - input_report_key(input, BTN_TOUCH, data[4] & 0x08);
      - input_report_key(input, BTN_STYLUS, data[4] & 0x10);
      - /* Only allow the stylus2 button to be reported for the pen tool. */
      - input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20));
 ++++++ if (prox) {
 ++++++         pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
 ++++++         if (features->pressure_max > 255)
 ++++++                 pressure = (pressure << 1) | ((data[4] >> 6) & 1);
 ++++++         pressure += (features->pressure_max + 1) / 2;
      +
 -----  input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
 -----  input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
 -----  input_report_abs(input, ABS_PRESSURE, pressure);
 ++++++         input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
 ++++++         input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
 ++++++         input_report_abs(input, ABS_PRESSURE, pressure);
      +
 -----  input_report_key(input, BTN_TOUCH, data[4] & 0x08);
 -----  input_report_key(input, BTN_STYLUS, data[4] & 0x10);
 -----  /* Only allow the stylus2 button to be reported for the pen tool. */
 -----  input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20));
 ++++++         input_report_key(input, BTN_TOUCH, data[4] & 0x08);
 ++++++         input_report_key(input, BTN_STYLUS, data[4] & 0x10);
 ++++++         /* Only allow the stylus2 button to be reported for the pen tool. */
 ++++++         input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20));
 ++++++ }
       
        if (!prox)
                wacom->id[0] = 0;
@@@@@@@@ -1192,6 -1190,6 -1190,6 -1190,6 -1190,6 -1190,6 -1192,166 +1194,166 @@@@@@@@ static int wacom_wac_finger_count_touch
        return count;
       }
       
++++++ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
++++++ {
++++++  const int pen_frame_len = 14;
++++++  const int pen_frames = 7;
++++++ 
++++++  struct input_dev *pen_input = wacom->pen_input;
++++++  unsigned char *data = wacom->data;
++++++  int i;
++++++ 
++++++  wacom->serial[0] = get_unaligned_le64(&data[99]);
++++++  wacom->id[0]     = get_unaligned_le16(&data[107]);
++++++  if (wacom->serial[0] >> 52 == 1) {
++++++          /* Add back in missing bits of ID for non-USI pens */
++++++          wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF;
++++++  }
++++++  wacom->tool[0]   = wacom_intuos_get_tool_type(wacom_intuos_id_mangle(wacom->id[0]));
++++++ 
++++++  for (i = 0; i < pen_frames; i++) {
++++++          unsigned char *frame = &data[i*pen_frame_len + 1];
++++++          bool valid = frame[0] & 0x80;
++++++          bool prox = frame[0] & 0x40;
++++++          bool range = frame[0] & 0x20;
++++++ 
++++++          if (!valid)
++++++                  continue;
++++++ 
++++++          if (range) {
++++++                  input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
++++++                  input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
++++++                  input_report_abs(pen_input, ABS_TILT_X, frame[7]);
++++++                  input_report_abs(pen_input, ABS_TILT_Y, frame[8]);
++++++                  input_report_abs(pen_input, ABS_Z, get_unaligned_le16(&frame[9]));
++++++                  input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11]));
++++++          }
++++++          input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
++++++          input_report_abs(pen_input, ABS_DISTANCE, range ? frame[13] : wacom->features.distance_max);
++++++ 
++++++          input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x01);
++++++          input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02);
++++++          input_report_key(pen_input, BTN_STYLUS2, frame[0] & 0x04);
++++++ 
++++++          input_report_key(pen_input, wacom->tool[0], prox);
++++++          input_event(pen_input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
++++++          input_report_abs(pen_input, ABS_MISC,
++++++                           wacom_intuos_id_mangle(wacom->id[0])); /* report tool id */
++++++ 
++++++          wacom->shared->stylus_in_proximity = prox;
++++++ 
++++++          input_sync(pen_input);
++++++  }
++++++ }
++++++ 
++++++ static void wacom_intuos_pro2_bt_touch(struct wacom_wac *wacom)
++++++ {
++++++  const int finger_touch_len = 8;
++++++  const int finger_frames = 4;
++++++  const int finger_frame_len = 43;
++++++ 
++++++  struct input_dev *touch_input = wacom->touch_input;
++++++  unsigned char *data = wacom->data;
++++++  int num_contacts_left = 5;
++++++  int i, j;
++++++ 
++++++  for (i = 0; i < finger_frames; i++) {
++++++          unsigned char *frame = &data[i*finger_frame_len + 109];
++++++          int current_num_contacts = frame[0] & 0x7F;
++++++          int contacts_to_send;
++++++ 
++++++          if (!(frame[0] & 0x80))
++++++                  continue;
++++++ 
++++++          /*
++++++           * First packet resets the counter since only the first
++++++           * packet in series will have non-zero current_num_contacts.
++++++           */
++++++          if (current_num_contacts)
++++++                  wacom->num_contacts_left = current_num_contacts;
++++++ 
++++++          contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
++++++ 
++++++          for (j = 0; j < contacts_to_send; j++) {
++++++                  unsigned char *touch = &frame[j*finger_touch_len + 1];
++++++                  int slot = input_mt_get_slot_by_key(touch_input, touch[0]);
++++++                  int x = get_unaligned_le16(&touch[2]);
++++++                  int y = get_unaligned_le16(&touch[4]);
++++++                  int w = touch[6] * input_abs_get_res(touch_input, ABS_MT_POSITION_X);
++++++                  int h = touch[7] * input_abs_get_res(touch_input, ABS_MT_POSITION_Y);
++++++ 
++++++                  if (slot < 0)
++++++                          continue;
++++++ 
++++++                  input_mt_slot(touch_input, slot);
++++++                  input_mt_report_slot_state(touch_input, MT_TOOL_FINGER, touch[1] & 0x01);
++++++                  input_report_abs(touch_input, ABS_MT_POSITION_X, x);
++++++                  input_report_abs(touch_input, ABS_MT_POSITION_Y, y);
++++++                  input_report_abs(touch_input, ABS_MT_TOUCH_MAJOR, max(w, h));
++++++                  input_report_abs(touch_input, ABS_MT_TOUCH_MINOR, min(w, h));
++++++                  input_report_abs(touch_input, ABS_MT_ORIENTATION, w > h);
++++++          }
++++++ 
++++++          input_mt_sync_frame(touch_input);
++++++ 
++++++          wacom->num_contacts_left -= contacts_to_send;
++++++          if (wacom->num_contacts_left <= 0) {
++++++                  wacom->num_contacts_left = 0;
++++++                  wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
++++++          }
++++++  }
++++++ 
++++++  input_report_switch(touch_input, SW_MUTE_DEVICE, !(data[281] >> 7));
++++++  input_sync(touch_input);
++++++ }
++++++ 
++++++ static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom)
++++++ {
++++++  struct input_dev *pad_input = wacom->pad_input;
++++++  unsigned char *data = wacom->data;
++++++ 
++++++  int buttons = (data[282] << 1) | ((data[281] >> 6) & 0x01);
++++++  int ring = data[285];
++++++  int prox = buttons | (ring & 0x80);
++++++ 
++++++  wacom_report_numbered_buttons(pad_input, 9, buttons);
++++++ 
++++++  input_report_abs(pad_input, ABS_WHEEL, (ring & 0x80) ? (ring & 0x7f) : 0);
++++++ 
++++++  input_report_key(pad_input, wacom->tool[1], prox ? 1 : 0);
++++++  input_report_abs(pad_input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
++++++  input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff);
++++++ 
++++++  input_sync(pad_input);
++++++ }
++++++ 
++++++ static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom)
++++++ {
++++++  unsigned char *data = wacom->data;
++++++ 
++++++  bool chg = data[284] & 0x80;
++++++  int battery_status = data[284] & 0x7F;
++++++ 
++++++  wacom_notify_battery(wacom, battery_status, chg, 1, chg);
++++++ }
++++++ 
++++++ static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
++++++ {
++++++  unsigned char *data = wacom->data;
++++++ 
++++++  if (data[0] != 0x80) {
++++++          dev_dbg(wacom->pen_input->dev.parent,
++++++                  "%s: received unknown report #%d\n", __func__, data[0]);
++++++          return 0;
++++++  }
++++++ 
++++++  wacom_intuos_pro2_bt_pen(wacom);
++++++  wacom_intuos_pro2_bt_touch(wacom);
++++++  wacom_intuos_pro2_bt_pad(wacom);
++++++  wacom_intuos_pro2_bt_battery(wacom);
++++++  return 0;
++++++ }
++++++ 
       static int wacom_24hdt_irq(struct wacom_wac *wacom)
       {
        struct input_dev *input = wacom->touch_input;
@@@@@@@@ -1446,7 -1444,7 -1444,7 -1444,7 -1444,7 -1444,7 -1606,7 +1608,7 @@@@@@@@ static int wacom_tpc_irq(struct wacom_w
        return 0;
       }
       
------ static int wacom_equivalent_usage(int usage)
++++++ int wacom_equivalent_usage(int usage)
       {
        if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMDIGITIZER) {
                int subpage = (usage & 0xFF00) << 8;
                return subpage | subusage;
        }
       
++++++  if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMTOUCH) {
++++++          int subpage = (usage & 0xFF00) << 8;
++++++          int subusage = (usage & 0xFF);
++++++ 
++++++          if (subpage == HID_UP_UNDEFINED)
++++++                  subpage = WACOM_HID_SP_DIGITIZER;
++++++ 
++++++          return subpage | subusage;
++++++  }
++++++ 
        return usage;
       }
       
@@@@@@@@ -1552,12 -1550,12 -1550,12 -1550,12 -1550,12 -1550,12 -1722,14 +1724,14 @@@@@@@@ static void wacom_wac_pad_usage_mapping
                wacom_map_usage(input, usage, field, EV_ABS, ABS_Z, 0);
                features->device_type |= WACOM_DEVICETYPE_PAD;
                break;
++++++  case WACOM_HID_WD_BUTTONCENTER:
++++++          wacom->generic_has_leds = true;
++++++          /* fall through */
        case WACOM_HID_WD_BUTTONHOME:
        case WACOM_HID_WD_BUTTONUP:
        case WACOM_HID_WD_BUTTONDOWN:
        case WACOM_HID_WD_BUTTONLEFT:
        case WACOM_HID_WD_BUTTONRIGHT:
------  case WACOM_HID_WD_BUTTONCENTER:
                wacom_map_usage(input, usage, field, EV_KEY,
                                wacom_numbered_button_to_key(features->numbered_buttons),
                                0);
                features->device_type |= WACOM_DEVICETYPE_PAD;
                break;
        case WACOM_HID_WD_TOUCHONOFF:
------          wacom_map_usage(input, usage, field, EV_SW, SW_MUTE_DEVICE, 0);
++++++          /*
++++++           * This usage, which is used to mute touch events, comes
++++++           * from the pad packet, but is reported on the touch
++++++           * interface. Because the touch interface may not have
++++++           * been created yet, we cannot call wacom_map_usage(). In
++++++           * order to process this usage when we receive it, we set
++++++           * the usage type and code directly.
++++++           */
++++++          wacom_wac->has_mute_touch_switch = true;
++++++          usage->type = EV_SW;
++++++          usage->code = SW_MUTE_DEVICE;
                features->device_type |= WACOM_DEVICETYPE_PAD;
                break;
        case WACOM_HID_WD_TOUCHSTRIP:
                wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
                features->device_type |= WACOM_DEVICETYPE_PAD;
                break;
++++++  case WACOM_HID_WD_TOUCHRINGSTATUS:
++++++          wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
++++++          features->device_type |= WACOM_DEVICETYPE_PAD;
++++++          break;
        }
       
        switch (equivalent_usage & 0xfffffff0) {
@@@@@@@@ -1622,17 -1620,17 -1620,17 -1620,17 -1620,17 -1620,17 -1808,40 +1810,40 @@@@@@@@ static void wacom_wac_pad_event(struct 
        struct input_dev *input = wacom_wac->pad_input;
        struct wacom_features *features = &wacom_wac->features;
        unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
++++++  int i;
++++++ 
++++++  /*
++++++   * Avoid reporting this event and setting inrange_state if this usage
++++++   * hasn't been mapped.
++++++   */
++++++  if (!usage->type)
++++++          return;
       
        if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) {
------          wacom_wac->hid_data.inrange_state |= value;
++++++          if (usage->hid != WACOM_HID_WD_TOUCHRING)
++++++                  wacom_wac->hid_data.inrange_state |= value;
        }
       
        switch (equivalent_usage) {
        case WACOM_HID_WD_TOUCHRINGSTATUS:
++++++          if (!value)
++++++                  input_event(input, usage->type, usage->code, 0);
 +++++          break;
 +++++ 
++++++  case WACOM_HID_WD_TOUCHONOFF:
++++++          if (wacom_wac->shared->touch_input) {
++++++                  input_report_switch(wacom_wac->shared->touch_input,
++++++                                      SW_MUTE_DEVICE, !value);
++++++                  input_sync(wacom_wac->shared->touch_input);
++++++          }
+               break;
+      
++++++  case WACOM_HID_WD_BUTTONCENTER:
++++++          for (i = 0; i < wacom->led.count; i++)
++++++                  wacom_update_led(wacom, features->numbered_buttons,
++++++                                   value, i);
++++++           /* fall through*/
        default:
------          features->input_event_flag = true;
                input_event(input, usage->type, usage->code, value);
                break;
        }
@@@@@@@@ -1670,20 -1668,20 -1668,20 -1668,20 -1668,20 -1668,20 -1879,15 +1881,15 @@@@@@@@ static void wacom_wac_pad_report(struc
       {
        struct wacom *wacom = hid_get_drvdata(hdev);
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
------  struct wacom_features *features = &wacom_wac->features;
        struct input_dev *input = wacom_wac->pad_input;
        bool active = wacom_wac->hid_data.inrange_state != 0;
       
        /* report prox for expresskey events */
        if (wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) {
------          features->input_event_flag = true;
                input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
------  }
------ 
------  if (features->input_event_flag) {
------          features->input_event_flag = false;
                input_sync(input);
        }
++++++ 
       }
       
       static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
@@@@@@@@ -2058,8 -2056,8 -2056,8 -2056,8 -2056,8 -2056,8 -2262,10 +2264,10 @@@@@@@@ static void wacom_wac_finger_pre_report
       
                for (j = 0; j < field->maxusage; j++) {
                        struct hid_usage *usage = &field->usage[j];
++++++                  unsigned int equivalent_usage =
++++++                          wacom_equivalent_usage(usage->hid);
       
------                  switch (usage->hid) {
++++++                  switch (equivalent_usage) {
                        case HID_GD_X:
                        case HID_GD_Y:
                        case HID_DG_WIDTH:
                        case HID_DG_INRANGE:
                        case HID_DG_INVERT:
                        case HID_DG_TIPSWITCH:
------                          hid_data->last_slot_field = usage->hid;
++++++                          hid_data->last_slot_field = equivalent_usage;
                                break;
                        case HID_DG_CONTACTCOUNT:
                                hid_data->cc_report = report->id;
@@@@@@@@ -2123,8 -2121,8 -2121,8 -2121,8 -2121,8 -2121,8 -2329,8 +2331,8 @@@@@@@@ void wacom_wac_usage_mapping(struct hid
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
        struct wacom_features *features = &wacom_wac->features;
       
------  /* currently, only direct devices have proper hid report descriptors */
------  features->device_type |= WACOM_DEVICETYPE_DIRECT;
++++++  if (WACOM_DIRECT_DEVICE(field))
++++++          features->device_type |= WACOM_DEVICETYPE_DIRECT;
       
        if (WACOM_PAD_FIELD(field))
                wacom_wac_pad_usage_mapping(hdev, field, usage);
@@@@@@@@ -2142,6 -2140,6 -2140,6 -2140,6 -2140,6 -2140,6 -2348,9 +2350,9 @@@@@@@@ void wacom_wac_event(struct hid_device 
        if (wacom->wacom_wac.features.type != HID_GENERIC)
                return;
       
++++++  if (value > field->logical_maximum || value < field->logical_minimum)
++++++          return;
++++++ 
        if (WACOM_PAD_FIELD(field)) {
                wacom_wac_pad_battery_event(hdev, field, usage, value);
                if (wacom->wacom_wac.pad_input)
@@@@@@@@ -2189,16 -2187,6 -2187,6 -2187,6 -2187,6 -2187,6 -2398,16 +2400,16 @@@@@@@@ void wacom_wac_report(struct hid_devic
       
        wacom_report_events(hdev, report);
       
 +++++  /*
 +++++   * Non-input reports may be sent prior to the device being
 +++++   * completely initialized. Since only their events need
 +++++   * to be processed, exit after 'wacom_report_events' has
 +++++   * been called to prevent potential crashes in the report-
 +++++   * processing functions.
 +++++   */
 +++++  if (report->type != HID_INPUT_REPORT)
 +++++          return;
 +++++ 
        if (WACOM_PAD_FIELD(field)) {
                wacom_wac_pad_battery_report(hdev, report);
                if (wacom->wacom_wac.pad_input)
@@@@@@@@ -2669,6 -2657,6 -2657,6 -2657,6 -2657,6 -2657,6 -2878,10 +2880,10 @@@@@@@@ void wacom_wac_irq(struct wacom_wac *wa
                        sync = wacom_intuos_irq(wacom_wac);
                break;
       
++++++  case INTUOSP2_BT:
++++++          sync = wacom_intuos_pro2_bt_irq(wacom_wac, len);
++++++          break;
++++++ 
        case TABLETPC:
        case TABLETPCE:
        case TABLETPC2FG:
@@@@@@@@ -2779,8 -2767,8 -2767,8 -2767,8 -2767,8 -2767,8 -2992,6 +2994,6 @@@@@@@@ void wacom_setup_device_quirks(struct w
        struct wacom_features *features = &wacom->wacom_wac.features;
       
        /* The pen and pad share the same interface on most devices */
------  if (features->numbered_buttons > 0)
------          features->device_type |= WACOM_DEVICETYPE_PAD;
        if (features->type == GRAPHIRE_BT || features->type == WACOM_G4 ||
            features->type == DTUS ||
            (features->type >= INTUOS3S && features->type <= WACOM_MO)) {
        if (features->type == REMOTE)
                features->device_type = WACOM_DEVICETYPE_PAD;
       
++++++  if (features->type == INTUOSP2_BT) {
++++++          features->device_type |= WACOM_DEVICETYPE_PEN |
++++++                                   WACOM_DEVICETYPE_PAD |
++++++                                   WACOM_DEVICETYPE_TOUCH;
++++++          features->quirks |= WACOM_QUIRK_BATTERY;
++++++  }
++++++ 
        switch (features->type) {
        case PL:
        case DTU:
@@@@@@@@ -2986,6 -2974,6 -2974,6 -2974,6 -2974,6 -2974,6 -3204,7 +3206,7 @@@@@@@@ int wacom_setup_pen_input_capabilities(
        case INTUOSPL:
        case INTUOS5S:
        case INTUOSPS:
++++++  case INTUOSP2_BT:
                input_set_abs_params(input_dev, ABS_DISTANCE, 0,
                                      features->distance_max,
                                      features->distance_fuzz, 0);
@@@@@@@@ -3094,6 -3082,6 -3082,6 -3082,6 -3082,6 -3082,6 -3313,27 +3315,27 @@@@@@@@ int wacom_setup_touch_input_capabilitie
        }
       
        switch (features->type) {
++++++  case INTUOSP2_BT:
++++++          input_dev->evbit[0] |= BIT_MASK(EV_SW);
++++++          __set_bit(SW_MUTE_DEVICE, input_dev->swbit);
++++++ 
++++++          if (wacom_wac->shared->touch->product == 0x361) {
++++++                  input_set_abs_params(input_dev, ABS_MT_POSITION_X,
++++++                                       0, 12440, 4, 0);
++++++                  input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
++++++                                       0, 8640, 4, 0);
++++++          }
++++++          else if (wacom_wac->shared->touch->product == 0x360) {
++++++                  input_set_abs_params(input_dev, ABS_MT_POSITION_X,
++++++                                       0, 8960, 4, 0);
++++++                  input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
++++++                                       0, 5920, 4, 0);
++++++          }
++++++          input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
++++++          input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
++++++ 
++++++          /* fall through */
++++++ 
        case INTUOS5:
        case INTUOS5L:
        case INTUOSPM:
@@@@@@@@ -3290,6 -3278,6 -3278,6 -3278,6 -3278,6 -3278,6 -3530,9 +3532,9 @@@@@@@@ int wacom_setup_pad_input_capabilities(
       {
        struct wacom_features *features = &wacom_wac->features;
       
++++++  if ((features->type == HID_GENERIC) && features->numbered_buttons > 0)
++++++          features->device_type |= WACOM_DEVICETYPE_PAD;
++++++ 
        if (!(features->device_type & WACOM_DEVICETYPE_PAD))
                return -ENODEV;
       
        case INTUOSPL:
        case INTUOS5S:
        case INTUOSPS:
++++++  case INTUOSP2_BT:
                input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
                break;
       
@@@@@@@@ -3949,6 -3937,6 -3937,6 -3937,6 -3937,6 -3937,6 -4193,12 +4195,12 @@@@@@@@ static const struct wacom_features waco
          DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
++++++ static const struct wacom_features wacom_features_0x360 =
++++++  { "Wacom Intuos Pro M", 44800, 29600, 8191, 63,
++++++    INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 };
++++++ static const struct wacom_features wacom_features_0x361 =
++++++  { "Wacom Intuos Pro L", 62200, 43200, 8191, 63,
++++++    INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 };
       
       static const struct wacom_features wacom_features_HID_ANY_ID =
        { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
@@@@@@@@ -4115,6 -4103,6 -4103,6 -4103,6 -4103,6 -4103,6 -4365,8 +4367,8 @@@@@@@@ const struct hid_device_id wacom_ids[] 
        { USB_DEVICE_WACOM(0x33D) },
        { USB_DEVICE_WACOM(0x33E) },
        { USB_DEVICE_WACOM(0x343) },
++++++  { BT_DEVICE_WACOM(0x360) },
++++++  { BT_DEVICE_WACOM(0x361) },
        { USB_DEVICE_WACOM(0x4001) },
        { USB_DEVICE_WACOM(0x4004) },
        { USB_DEVICE_WACOM(0x5000) },
       
        { USB_DEVICE_WACOM(HID_ANY_ID) },
        { I2C_DEVICE_WACOM(HID_ANY_ID) },
++++++  { BT_DEVICE_WACOM(HID_ANY_ID) },
        { }
       };
       MODULE_DEVICE_TABLE(hid, wacom_ids);