Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Apr 2015 16:25:26 +0000 (08:25 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Apr 2015 16:25:26 +0000 (09:25 -0700)
Pull HID updates from Jiri Kosina:

 - quite a few firmware fixes for RMI driver by Andrew Duggan

 - huion and uclogic drivers have been substantially overlaping in
   functionality laterly.  This redundancy is fixed by hid-huion driver
   being merged into hid-uclogic; work done by Benjamin Tissoires and
   Nikolai Kondrashov

 - i2c-hid now supports ACPI GPIO interrupts; patch from Mika Westerberg

 - Some of the quirks, that got separated into individual drivers, have
   historically had EXPERT dependency.  As HID subsystem matured (as
   well as the individual drivers), this made less and less sense.  This
   dependency is now being removed by patch from Jean Delvare

 - Logitech lg4ff driver received a couple of improvements for mode
   switching, by Michal MalĂ˝

 - multitouch driver now supports clickpads, patches by Benjamin
   Tissoires and Seth Forshee

 - hid-sensor framework received a substantial update; namely support
   for Custom and Generic pages is being added; work done by Srinivas
   Pandruvada

 - wacom driver received substantial update; it now supports
   i2c-conntected devices (Mika Westerberg), Bamboo PADs are now
   properly supported (Benjamin Tissoires), much improved battery
   reporting (Jason Gerecke) and pen proximity cleanups (Ping Cheng)

 - small assorted fixes and device ID additions

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (68 commits)
  HID: sensor: Update document for custom sensor
  HID: sensor: Custom and Generic sensor support
  HID: debug: fix error handling in hid_debug_events_read()
  Input - mt: Fix input_mt_get_slot_by_key
  HID: logitech-hidpp: fix error return code
  HID: wacom: Add support for Cintiq 13HD Touch
  HID: logitech-hidpp: add a module parameter to keep firmware gestures
  HID: usbhid: yet another mouse with ALWAYS_POLL
  HID: usbhid: more mice with ALWAYS_POLL
  HID: wacom: set stylus_in_proximity before checking touch_down
  HID: wacom: use wacom_wac_finger_count_touches to set touch_down
  HID: wacom: remove hardcoded WACOM_QUIRK_MULTI_INPUT
  HID: pidff: effect can't be NULL
  HID: add quirk for PIXART OEM mouse used by HP
  HID: add HP OEM mouse to quirk ALWAYS_POLL
  HID: wacom: ask for a in-prox report when it was missed
  HID: hid-sensor-hub: Fix sparse warning
  HID: hid-sensor-hub: fix attribute read for logical usage id
  HID: plantronics: fix Kconfig default
  HID: pidff: support more than one concurrent effect
  ...

1  2 
drivers/hid/hid-input.c
drivers/hid/hid-sony.c
drivers/hid/wacom.h
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c
include/linux/hid.h
include/uapi/linux/input.h

diff --combined drivers/hid/hid-input.c
@@@ -339,7 -339,7 +339,7 @@@ static int hidinput_get_battery_propert
                                         enum power_supply_property prop,
                                         union power_supply_propval *val)
  {
 -      struct hid_device *dev = container_of(psy, struct hid_device, battery);
 +      struct hid_device *dev = power_supply_get_drvdata(psy);
        int ret = 0;
        __u8 *buf;
  
  
  static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field)
  {
 -      struct power_supply *battery = &dev->battery;
 -      int ret;
 +      struct power_supply_desc *psy_desc = NULL;
 +      struct power_supply_config psy_cfg = { .drv_data = dev, };
        unsigned quirks;
        s32 min, max;
  
        if (field->usage->hid != HID_DC_BATTERYSTRENGTH)
                return false;   /* no match */
  
 -      if (battery->name != NULL)
 +      if (dev->battery != NULL)
                goto out;       /* already initialized? */
  
 -      battery->name = kasprintf(GFP_KERNEL, "hid-%s-battery", dev->uniq);
 -      if (battery->name == NULL)
 +      psy_desc = kzalloc(sizeof(*psy_desc), GFP_KERNEL);
 +      if (psy_desc == NULL)
                goto out;
  
 -      battery->type = POWER_SUPPLY_TYPE_BATTERY;
 -      battery->properties = hidinput_battery_props;
 -      battery->num_properties = ARRAY_SIZE(hidinput_battery_props);
 -      battery->use_for_apm = 0;
 -      battery->get_property = hidinput_get_battery_property;
 +      psy_desc->name = kasprintf(GFP_KERNEL, "hid-%s-battery", dev->uniq);
 +      if (psy_desc->name == NULL) {
 +              kfree(psy_desc);
 +              goto out;
 +      }
 +
 +      psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
 +      psy_desc->properties = hidinput_battery_props;
 +      psy_desc->num_properties = ARRAY_SIZE(hidinput_battery_props);
 +      psy_desc->use_for_apm = 0;
 +      psy_desc->get_property = hidinput_get_battery_property;
  
        quirks = find_battery_quirk(dev);
  
        dev->battery_report_type = report_type;
        dev->battery_report_id = field->report->id;
  
 -      ret = power_supply_register(&dev->dev, battery);
 -      if (ret != 0) {
 -              hid_warn(dev, "can't register power supply: %d\n", ret);
 -              kfree(battery->name);
 -              battery->name = NULL;
 +      dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);
 +      if (IS_ERR(dev->battery)) {
 +              hid_warn(dev, "can't register power supply: %ld\n",
 +                              PTR_ERR(dev->battery));
 +              kfree(psy_desc->name);
 +              kfree(psy_desc);
 +              dev->battery = NULL;
 +      } else {
 +              power_supply_powers(dev->battery, &dev->dev);
        }
  
 -      power_supply_powers(battery, &dev->dev);
 -
  out:
        return true;
  }
  
  static void hidinput_cleanup_battery(struct hid_device *dev)
  {
 -      if (!dev->battery.name)
 +      if (!dev->battery)
                return;
  
 -      power_supply_unregister(&dev->battery);
 -      kfree(dev->battery.name);
 -      dev->battery.name = NULL;
 +      power_supply_unregister(dev->battery);
 +      kfree(dev->battery->desc->name);
 +      kfree(dev->battery->desc);
 +      dev->battery = NULL;
  }
  #else  /* !CONFIG_HID_BATTERY_STRENGTH */
  static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
@@@ -720,6 -711,29 +720,29 @@@ static void hidinput_configure_usage(st
                }
                break;
  
+       case HID_UP_TELEPHONY:
+               switch (usage->hid & HID_USAGE) {
+               case 0x2f: map_key_clear(KEY_MICMUTE);          break;
+               case 0xb0: map_key_clear(KEY_NUMERIC_0);        break;
+               case 0xb1: map_key_clear(KEY_NUMERIC_1);        break;
+               case 0xb2: map_key_clear(KEY_NUMERIC_2);        break;
+               case 0xb3: map_key_clear(KEY_NUMERIC_3);        break;
+               case 0xb4: map_key_clear(KEY_NUMERIC_4);        break;
+               case 0xb5: map_key_clear(KEY_NUMERIC_5);        break;
+               case 0xb6: map_key_clear(KEY_NUMERIC_6);        break;
+               case 0xb7: map_key_clear(KEY_NUMERIC_7);        break;
+               case 0xb8: map_key_clear(KEY_NUMERIC_8);        break;
+               case 0xb9: map_key_clear(KEY_NUMERIC_9);        break;
+               case 0xba: map_key_clear(KEY_NUMERIC_STAR);     break;
+               case 0xbb: map_key_clear(KEY_NUMERIC_POUND);    break;
+               case 0xbc: map_key_clear(KEY_NUMERIC_A);        break;
+               case 0xbd: map_key_clear(KEY_NUMERIC_B);        break;
+               case 0xbe: map_key_clear(KEY_NUMERIC_C);        break;
+               case 0xbf: map_key_clear(KEY_NUMERIC_D);        break;
+               default: goto ignore;
+               }
+               break;
        case HID_UP_CONSUMER:   /* USB HUT v1.12, pages 75-84 */
                switch (usage->hid & HID_USAGE) {
                case 0x000: goto ignore;
diff --combined drivers/hid/hid-sony.c
@@@ -802,7 -802,8 +802,8 @@@ union sixaxis_output_report_01 
  #define DS4_REPORT_0x05_SIZE 32
  #define DS4_REPORT_0x11_SIZE 78
  #define DS4_REPORT_0x81_SIZE 7
- #define SIXAXIS_REPORT_0xF2_SIZE 18
+ #define SIXAXIS_REPORT_0xF2_SIZE 17
+ #define SIXAXIS_REPORT_0xF5_SIZE 8
  
  static DEFINE_SPINLOCK(sony_dev_list_lock);
  static LIST_HEAD(sony_device_list);
@@@ -815,8 -816,7 +816,8 @@@ struct sony_sc 
        struct led_classdev *leds[MAX_LEDS];
        unsigned long quirks;
        struct work_struct state_worker;
 -      struct power_supply battery;
 +      struct power_supply *battery;
 +      struct power_supply_desc battery_desc;
        int device_id;
        __u8 *output_report_dmabuf;
  
@@@ -1131,18 -1131,38 +1132,38 @@@ static void sony_input_configured(struc
   */
  static int sixaxis_set_operational_usb(struct hid_device *hdev)
  {
+       const int buf_size =
+               max(SIXAXIS_REPORT_0xF2_SIZE, SIXAXIS_REPORT_0xF5_SIZE);
+       __u8 *buf;
        int ret;
-       char *buf = kmalloc(18, GFP_KERNEL);
  
+       buf = kmalloc(buf_size, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
  
-       ret = hid_hw_raw_request(hdev, 0xf2, buf, 17, HID_FEATURE_REPORT,
-                                HID_REQ_GET_REPORT);
+       ret = hid_hw_raw_request(hdev, 0xf2, buf, SIXAXIS_REPORT_0xF2_SIZE,
+                                HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+       if (ret < 0) {
+               hid_err(hdev, "can't set operational mode: step 1\n");
+               goto out;
+       }
+       /*
+        * Some compatible controllers like the Speedlink Strike FX and
+        * Gasia need another query plus an USB interrupt to get operational.
+        */
+       ret = hid_hw_raw_request(hdev, 0xf5, buf, SIXAXIS_REPORT_0xF5_SIZE,
+                                HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+       if (ret < 0) {
+               hid_err(hdev, "can't set operational mode: step 2\n");
+               goto out;
+       }
  
+       ret = hid_hw_output_report(hdev, buf, 1);
        if (ret < 0)
-               hid_err(hdev, "can't set operational mode\n");
+               hid_err(hdev, "can't set operational mode: step 3\n");
  
+ out:
        kfree(buf);
  
        return ret;
@@@ -1661,7 -1681,7 +1682,7 @@@ static int sony_battery_get_property(st
                                     enum power_supply_property psp,
                                     union power_supply_propval *val)
  {
 -      struct sony_sc *sc = container_of(psy, struct sony_sc, battery);
 +      struct sony_sc *sc = power_supply_get_drvdata(psy);
        unsigned long flags;
        int ret = 0;
        u8 battery_charging, battery_capacity, cable_state;
  
  static int sony_battery_probe(struct sony_sc *sc)
  {
 +      struct power_supply_config psy_cfg = { .drv_data = sc, };
        struct hid_device *hdev = sc->hdev;
        int ret;
  
         */
        sc->battery_capacity = 100;
  
 -      sc->battery.properties = sony_battery_props;
 -      sc->battery.num_properties = ARRAY_SIZE(sony_battery_props);
 -      sc->battery.get_property = sony_battery_get_property;
 -      sc->battery.type = POWER_SUPPLY_TYPE_BATTERY;
 -      sc->battery.use_for_apm = 0;
 -      sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%pMR",
 -                                   sc->mac_address);
 -      if (!sc->battery.name)
 +      sc->battery_desc.properties = sony_battery_props;
 +      sc->battery_desc.num_properties = ARRAY_SIZE(sony_battery_props);
 +      sc->battery_desc.get_property = sony_battery_get_property;
 +      sc->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY;
 +      sc->battery_desc.use_for_apm = 0;
 +      sc->battery_desc.name = kasprintf(GFP_KERNEL,
 +                                        "sony_controller_battery_%pMR",
 +                                        sc->mac_address);
 +      if (!sc->battery_desc.name)
                return -ENOMEM;
  
 -      ret = power_supply_register(&hdev->dev, &sc->battery);
 -      if (ret) {
 +      sc->battery = power_supply_register(&hdev->dev, &sc->battery_desc,
 +                                          &psy_cfg);
 +      if (IS_ERR(sc->battery)) {
 +              ret = PTR_ERR(sc->battery);
                hid_err(hdev, "Unable to register battery device\n");
                goto err_free;
        }
  
 -      power_supply_powers(&sc->battery, &hdev->dev);
 +      power_supply_powers(sc->battery, &hdev->dev);
        return 0;
  
  err_free:
 -      kfree(sc->battery.name);
 -      sc->battery.name = NULL;
 +      kfree(sc->battery_desc.name);
 +      sc->battery_desc.name = NULL;
        return ret;
  }
  
  static void sony_battery_remove(struct sony_sc *sc)
  {
 -      if (!sc->battery.name)
 +      if (!sc->battery_desc.name)
                return;
  
 -      power_supply_unregister(&sc->battery);
 -      kfree(sc->battery.name);
 -      sc->battery.name = NULL;
 +      power_supply_unregister(sc->battery);
 +      kfree(sc->battery_desc.name);
 +      sc->battery_desc.name = NULL;
  }
  
  /*
diff --combined drivers/hid/wacom.h
@@@ -119,10 -119,8 +119,10 @@@ struct wacom 
                u8 img_lum;   /* OLED matrix display brightness */
        } led;
        bool led_initialized;
 -      struct power_supply battery;
 -      struct power_supply ac;
 +      struct power_supply *battery;
 +      struct power_supply *ac;
 +      struct power_supply_desc battery_desc;
 +      struct power_supply_desc ac_desc;
  };
  
  static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
        schedule_work(&wacom->work);
  }
  
- static inline void wacom_notify_battery(struct wacom_wac *wacom_wac)
- {
-       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
-       power_supply_changed(wacom->battery);
- }
  extern const struct hid_device_id wacom_ids[];
  
  void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
@@@ -151,4 -142,5 +144,5 @@@ void wacom_wac_usage_mapping(struct hid
  int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
                struct hid_usage *usage, __s32 value);
  void wacom_wac_report(struct hid_device *hdev, struct hid_report *report);
+ void wacom_battery_work(struct work_struct *work);
  #endif
diff --combined drivers/hid/wacom_sys.c
@@@ -406,6 -406,9 +406,9 @@@ static int wacom_query_tablet_data(stru
                else if (features->type == WACOM_27QHDT) {
                        return wacom_set_device_mode(hdev, 131, 3, 2);
                }
+               else if (features->type == BAMBOO_PAD) {
+                       return wacom_set_device_mode(hdev, 2, 2, 2);
+               }
        } else if (features->device_type == BTN_TOOL_PEN) {
                if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
                        return wacom_set_device_mode(hdev, 2, 2, 2);
@@@ -524,6 -527,11 +527,11 @@@ static int wacom_add_shared_data(struc
  
        wacom_wac->shared = &data->shared;
  
+       if (wacom_wac->features.device_type == BTN_TOOL_FINGER)
+               wacom_wac->shared->touch = hdev;
+       else if (wacom_wac->features.device_type == BTN_TOOL_PEN)
+               wacom_wac->shared->pen = hdev;
  out:
        mutex_unlock(&wacom_udev_list_lock);
        return retval;
@@@ -541,14 -549,22 +549,22 @@@ static void wacom_release_shared_data(s
        kfree(data);
  }
  
- static void wacom_remove_shared_data(struct wacom_wac *wacom)
+ static void wacom_remove_shared_data(struct wacom *wacom)
  {
        struct wacom_hdev_data *data;
+       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+       if (wacom_wac->shared) {
+               data = container_of(wacom_wac->shared, struct wacom_hdev_data,
+                                   shared);
+               if (wacom_wac->shared->touch == wacom->hdev)
+                       wacom_wac->shared->touch = NULL;
+               else if (wacom_wac->shared->pen == wacom->hdev)
+                       wacom_wac->shared->pen = NULL;
  
-       if (wacom->shared) {
-               data = container_of(wacom->shared, struct wacom_hdev_data, shared);
                kref_put(&data->kref, wacom_release_shared_data);
-               wacom->shared = NULL;
+               wacom_wac->shared = NULL;
        }
  }
  
@@@ -929,6 -945,7 +945,7 @@@ static void wacom_destroy_leds(struct w
  }
  
  static enum power_supply_property wacom_battery_props[] = {
+       POWER_SUPPLY_PROP_PRESENT,
        POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_SCOPE,
        POWER_SUPPLY_PROP_CAPACITY
@@@ -944,10 -961,13 +961,13 @@@ static int wacom_battery_get_property(s
                                      enum power_supply_property psp,
                                      union power_supply_propval *val)
  {
 -      struct wacom *wacom = container_of(psy, struct wacom, battery);
 +      struct wacom *wacom = power_supply_get_drvdata(psy);
        int ret = 0;
  
        switch (psp) {
+               case POWER_SUPPLY_PROP_PRESENT:
+                       val->intval = wacom->wacom_wac.bat_connected;
+                       break;
                case POWER_SUPPLY_PROP_SCOPE:
                        val->intval = POWER_SUPPLY_SCOPE_DEVICE;
                        break;
                        else if (wacom->wacom_wac.battery_capacity == 100 &&
                                    wacom->wacom_wac.ps_connected)
                                val->intval = POWER_SUPPLY_STATUS_FULL;
+                       else if (wacom->wacom_wac.ps_connected)
+                               val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
                        else
                                val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
                        break;
@@@ -976,7 -998,7 +998,7 @@@ static int wacom_ac_get_property(struc
                                enum power_supply_property psp,
                                union power_supply_propval *val)
  {
 -      struct wacom *wacom = container_of(psy, struct wacom, ac);
 +      struct wacom *wacom = power_supply_get_drvdata(psy);
        int ret = 0;
  
        switch (psp) {
  static int wacom_initialize_battery(struct wacom *wacom)
  {
        static atomic_t battery_no = ATOMIC_INIT(0);
 -      int error;
 +      struct power_supply_config psy_cfg = { .drv_data = wacom, };
        unsigned long n;
  
        if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) {
 +              struct power_supply_desc *bat_desc = &wacom->battery_desc;
 +              struct power_supply_desc *ac_desc = &wacom->ac_desc;
                n = atomic_inc_return(&battery_no) - 1;
  
 -              wacom->battery.properties = wacom_battery_props;
 -              wacom->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
 -              wacom->battery.get_property = wacom_battery_get_property;
 +              bat_desc->properties = wacom_battery_props;
 +              bat_desc->num_properties = ARRAY_SIZE(wacom_battery_props);
 +              bat_desc->get_property = wacom_battery_get_property;
                sprintf(wacom->wacom_wac.bat_name, "wacom_battery_%ld", n);
 -              wacom->battery.name = wacom->wacom_wac.bat_name;
 -              wacom->battery.type = POWER_SUPPLY_TYPE_BATTERY;
 -              wacom->battery.use_for_apm = 0;
 +              bat_desc->name = wacom->wacom_wac.bat_name;
 +              bat_desc->type = POWER_SUPPLY_TYPE_BATTERY;
 +              bat_desc->use_for_apm = 0;
  
 -              wacom->ac.properties = wacom_ac_props;
 -              wacom->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
 -              wacom->ac.get_property = wacom_ac_get_property;
 +              ac_desc->properties = wacom_ac_props;
 +              ac_desc->num_properties = ARRAY_SIZE(wacom_ac_props);
 +              ac_desc->get_property = wacom_ac_get_property;
                sprintf(wacom->wacom_wac.ac_name, "wacom_ac_%ld", n);
 -              wacom->ac.name = wacom->wacom_wac.ac_name;
 -              wacom->ac.type = POWER_SUPPLY_TYPE_MAINS;
 -              wacom->ac.use_for_apm = 0;
 -
 -              error = power_supply_register(&wacom->hdev->dev,
 -                                            &wacom->battery);
 -              if (error)
 -                      return error;
 -
 -              power_supply_powers(&wacom->battery, &wacom->hdev->dev);
 -
 -              error = power_supply_register(&wacom->hdev->dev, &wacom->ac);
 -              if (error) {
 -                      power_supply_unregister(&wacom->battery);
 -                      return error;
 +              ac_desc->name = wacom->wacom_wac.ac_name;
 +              ac_desc->type = POWER_SUPPLY_TYPE_MAINS;
 +              ac_desc->use_for_apm = 0;
 +
 +              wacom->battery = power_supply_register(&wacom->hdev->dev,
 +                                            &wacom->battery_desc, &psy_cfg);
 +              if (IS_ERR(wacom->battery))
 +                      return PTR_ERR(wacom->battery);
 +
 +              power_supply_powers(wacom->battery, &wacom->hdev->dev);
 +
 +              wacom->ac = power_supply_register(&wacom->hdev->dev,
 +                                                &wacom->ac_desc,
 +                                                &psy_cfg);
 +              if (IS_ERR(wacom->ac)) {
 +                      power_supply_unregister(wacom->battery);
 +                      return PTR_ERR(wacom->ac);
                }
  
 -              power_supply_powers(&wacom->ac, &wacom->hdev->dev);
 +              power_supply_powers(wacom->ac, &wacom->hdev->dev);
        }
  
        return 0;
  
  static void wacom_destroy_battery(struct wacom *wacom)
  {
-       if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
-            wacom->battery) {
 -      if (wacom->battery.dev) {
 -              power_supply_unregister(&wacom->battery);
 -              wacom->battery.dev = NULL;
 -              power_supply_unregister(&wacom->ac);
 -              wacom->ac.dev = NULL;
++      if (wacom->battery) {
 +              power_supply_unregister(wacom->battery);
 +              wacom->battery = NULL;
 +              power_supply_unregister(wacom->ac);
 +              wacom->ac = NULL;
        }
  }
  
@@@ -1317,6 -1334,20 +1338,20 @@@ fail
        return;
  }
  
 -           !wacom->battery.dev) {
+ void wacom_battery_work(struct work_struct *work)
+ {
+       struct wacom *wacom = container_of(work, struct wacom, work);
+       if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
 -               wacom->battery.dev) {
++           !wacom->battery) {
+               wacom_initialize_battery(wacom);
+       }
+       else if (!(wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
++               wacom->battery) {
+               wacom_destroy_battery(wacom);
+       }
+ }
  /*
   * Not all devices report physical dimensions from HID.
   * Compute the default from hardcoded logical dimension
@@@ -1377,6 -1408,9 +1412,9 @@@ static int wacom_probe(struct hid_devic
  
        hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
  
+       /* hid-core sets this quirk for the boot interface */
+       hdev->quirks &= ~HID_QUIRK_NOGET;
        wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
        if (!wacom)
                return -ENOMEM;
                        goto fail_allocate_inputs;
        }
  
+       /*
+        * Bamboo Pad has a generic hid handling for the Pen, and we switch it
+        * into debug mode for the touch part.
+        * We ignore the other interfaces.
+        */
+       if (features->type == BAMBOO_PAD) {
+               if (features->pktlen == WACOM_PKGLEN_PENABLED) {
+                       features->type = HID_GENERIC;
+               } else if ((features->pktlen != WACOM_PKGLEN_BPAD_TOUCH) &&
+                          (features->pktlen != WACOM_PKGLEN_BPAD_TOUCH_USB)) {
+                       error = -ENODEV;
+                       goto fail_shared_data;
+               }
+       }
        /* set the default size in case we do not get them from hid */
        wacom_set_default_phy(features);
  
                features->y_max = 4096;
        }
  
+       /*
+        * Same thing for Bamboo PAD
+        */
+       if (features->type == BAMBOO_PAD)
+               features->device_type = BTN_TOOL_FINGER;
        if (hdev->bus == BUS_BLUETOOTH)
                features->quirks |= WACOM_QUIRK_BATTERY;
  
        snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name),
                "%s Pad", features->name);
  
-       if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
-               /* Append the device type to the name */
-               if (features->device_type != BTN_TOOL_FINGER)
-                       strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
-               else if (features->touch_max)
-                       strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX);
-               else
-                       strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
+       /* Append the device type to the name */
+       if (features->device_type != BTN_TOOL_FINGER)
+               strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
+       else if (features->touch_max)
+               strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX);
+       else
+               strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
  
-               error = wacom_add_shared_data(hdev);
-               if (error)
-                       goto fail_shared_data;
-       }
+       error = wacom_add_shared_data(hdev);
+       if (error)
+               goto fail_shared_data;
  
        if (!(features->quirks & WACOM_QUIRK_MONITOR) &&
             (features->quirks & WACOM_QUIRK_BATTERY)) {
@@@ -1531,7 -1584,7 +1588,7 @@@ fail_register_inputs
        wacom_clean_inputs(wacom);
        wacom_destroy_battery(wacom);
  fail_battery:
-       wacom_remove_shared_data(wacom_wac);
+       wacom_remove_shared_data(wacom);
  fail_shared_data:
        wacom_clean_inputs(wacom);
  fail_allocate_inputs:
@@@ -1554,7 -1607,7 +1611,7 @@@ static void wacom_remove(struct hid_dev
        if (hdev->bus == BUS_BLUETOOTH)
                device_remove_file(&hdev->dev, &dev_attr_speed);
        wacom_destroy_battery(wacom);
-       wacom_remove_shared_data(&wacom->wacom_wac);
+       wacom_remove_shared_data(wacom);
  
        hid_set_drvdata(hdev, NULL);
        kfree(wacom);
diff --combined drivers/hid/wacom_wac.c
@@@ -45,6 -45,27 +45,27 @@@ static unsigned short batcap_gr[8] = { 
   */
  static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
  
 -              if (wacom->battery.dev)
 -                      power_supply_changed(&wacom->battery);
+ static void wacom_notify_battery(struct wacom_wac *wacom_wac,
+       int bat_capacity, bool bat_charging, bool bat_connected,
+       bool ps_connected)
+ {
+       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+       bool changed = wacom_wac->battery_capacity != bat_capacity  ||
+                      wacom_wac->bat_charging     != bat_charging  ||
+                      wacom_wac->bat_connected    != bat_connected ||
+                      wacom_wac->ps_connected     != ps_connected;
+       if (changed) {
+               wacom_wac->battery_capacity = bat_capacity;
+               wacom_wac->bat_charging = bat_charging;
+               wacom_wac->bat_connected = bat_connected;
+               wacom_wac->ps_connected = ps_connected;
++              if (wacom->battery)
++                      power_supply_changed(wacom->battery);
+       }
+ }
  static int wacom_penpartner_irq(struct wacom_wac *wacom)
  {
        unsigned char *data = wacom->data;
@@@ -419,17 -440,26 +440,26 @@@ static int wacom_graphire_irq(struct wa
                rw = (data[7] >> 2 & 0x07);
                battery_capacity = batcap_gr[rw];
                ps_connected = rw == 7;
-               if ((wacom->battery_capacity != battery_capacity) ||
-                   (wacom->ps_connected != ps_connected)) {
-                       wacom->battery_capacity = battery_capacity;
-                       wacom->ps_connected = ps_connected;
-                       wacom_notify_battery(wacom);
-               }
+               wacom_notify_battery(wacom, battery_capacity, ps_connected,
+                                    1, ps_connected);
        }
  exit:
        return retval;
  }
  
+ static void wacom_intuos_schedule_prox_event(struct wacom_wac *wacom_wac)
+ {
+       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+       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 (r) {
+               hid_hw_request(wacom->hdev, r, HID_REQ_GET_REPORT);
+       }
+ }
  static int wacom_intuos_inout(struct wacom_wac *wacom)
  {
        struct wacom_features *features = &wacom->features;
           (features->type == CINTIQ && !(data[1] & 0x40)))
                return 1;
  
-       if (wacom->shared) {
-               wacom->shared->stylus_in_proximity = true;
-               if (wacom->shared->touch_down)
-                       return 1;
-       }
+       wacom->shared->stylus_in_proximity = true;
+       if (wacom->shared->touch_down)
+               return 1;
  
        /* in Range while exiting */
        if (((data[1] & 0xfe) == 0x20) && wacom->reporting_data) {
  
        /* Exit report */
        if ((data[1] & 0xfe) == 0x80) {
-               if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
-                       wacom->shared->stylus_in_proximity = false;
+               wacom->shared->stylus_in_proximity = false;
                wacom->reporting_data = false;
  
                /* don't report exit if we don't know the ID */
        }
  
        /* don't report other events if we don't know the ID */
-       if (!wacom->id[idx])
+       if (!wacom->id[idx]) {
+               /* but reschedule a read of the current tool */
+               wacom_intuos_schedule_prox_event(wacom);
                return 1;
+       }
  
        return 0;
  }
@@@ -1023,15 -1052,9 +1052,9 @@@ static int wacom_intuos_bt_irq(struct w
                bat_charging = (power_raw & 0x08) ? 1 : 0;
                ps_connected = (power_raw & 0x10) ? 1 : 0;
                battery_capacity = batcap_i4[power_raw & 0x07];
-               if ((wacom->battery_capacity != battery_capacity) ||
-                   (wacom->bat_charging != bat_charging) ||
-                   (wacom->ps_connected != ps_connected)) {
-                       wacom->battery_capacity = battery_capacity;
-                       wacom->bat_charging = bat_charging;
-                       wacom->ps_connected = ps_connected;
-                       wacom_notify_battery(wacom);
-               }
+               wacom_notify_battery(wacom, battery_capacity, bat_charging,
+                                    battery_capacity || bat_charging,
+                                    ps_connected);
                break;
        default:
                dev_dbg(wacom->input->dev.parent,
        return 0;
  }
  
+ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom)
+ {
+       struct input_dev *input = wacom->input;
+       unsigned touch_max = wacom->features.touch_max;
+       int count = 0;
+       int i;
+       /* non-HID_GENERIC single touch input doesn't call this routine */
+       if ((touch_max == 1) && (wacom->features.type == HID_GENERIC))
+               return wacom->hid_data.tipswitch &&
+                      !wacom->shared->stylus_in_proximity;
+       for (i = 0; i < input->mt->num_slots; i++) {
+               struct input_mt_slot *ps = &input->mt->slots[i];
+               int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
+               if (id >= 0)
+                       count++;
+       }
+       return count;
+ }
  static int wacom_24hdt_irq(struct wacom_wac *wacom)
  {
        struct input_dev *input = wacom->input;
        int num_contacts_left = 4; /* maximum contacts per packet */
        int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
        int y_offset = 2;
-       static int contact_with_no_pen_down_count = 0;
  
        if (wacom->features.type == WACOM_27QHDT) {
                current_num_contacts = data[63];
         * First packet resets the counter since only the first
         * packet in series will have non-zero current_num_contacts.
         */
-       if (current_num_contacts) {
+       if (current_num_contacts)
                wacom->num_contacts_left = current_num_contacts;
-               contact_with_no_pen_down_count = 0;
-       }
  
        contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
  
                                input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
                                input_report_abs(input, ABS_MT_ORIENTATION, w > h);
                        }
-                       contact_with_no_pen_down_count++;
                }
        }
-       input_mt_report_pointer_emulation(input, true);
+       input_mt_sync_frame(input);
  
        wacom->num_contacts_left -= contacts_to_send;
        if (wacom->num_contacts_left <= 0) {
                wacom->num_contacts_left = 0;
-               wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+               wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
        }
        return 1;
  }
@@@ -1122,7 -1163,6 +1163,6 @@@ static int wacom_mt_touch(struct wacom_
        int current_num_contacts = data[2];
        int contacts_to_send = 0;
        int x_offset = 0;
-       static int contact_with_no_pen_down_count = 0;
  
        /* MTTPC does not support Height and Width */
        if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
         * First packet resets the counter since only the first
         * packet in series will have non-zero current_num_contacts.
         */
-       if (current_num_contacts) {
+       if (current_num_contacts)
                wacom->num_contacts_left = current_num_contacts;
-               contact_with_no_pen_down_count = 0;
-       }
  
        /* There are at most 5 contacts per packet */
        contacts_to_send = min(5, wacom->num_contacts_left);
                        int y = get_unaligned_le16(&data[offset + x_offset + 9]);
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
-                       contact_with_no_pen_down_count++;
                }
        }
-       input_mt_report_pointer_emulation(input, true);
+       input_mt_sync_frame(input);
  
        wacom->num_contacts_left -= contacts_to_send;
        if (wacom->num_contacts_left <= 0) {
                wacom->num_contacts_left = 0;
-               wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+               wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
        }
        return 1;
  }
@@@ -1173,7 -1210,6 +1210,6 @@@ static int wacom_tpc_mt_touch(struct wa
  {
        struct input_dev *input = wacom->input;
        unsigned char *data = wacom->data;
-       int contact_with_no_pen_down_count = 0;
        int i;
  
        for (i = 0; i < 2; i++) {
  
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
-                       contact_with_no_pen_down_count++;
                }
        }
-       input_mt_report_pointer_emulation(input, true);
+       input_mt_sync_frame(input);
  
        /* keep touch state for pen event */
-       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
  
        return 1;
  }
@@@ -1522,29 -1557,6 +1557,6 @@@ static int wacom_wac_finger_event(struc
        return 0;
  }
  
- static int wacom_wac_finger_count_touches(struct hid_device *hdev)
- {
-       struct wacom *wacom = hid_get_drvdata(hdev);
-       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
-       struct input_dev *input = wacom_wac->input;
-       unsigned touch_max = wacom_wac->features.touch_max;
-       int count = 0;
-       int i;
-       if (touch_max == 1)
-               return wacom_wac->hid_data.tipswitch &&
-                      !wacom_wac->shared->stylus_in_proximity;
-       for (i = 0; i < input->mt->num_slots; i++) {
-               struct input_mt_slot *ps = &input->mt->slots[i];
-               int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
-               if (id >= 0)
-                       count++;
-       }
-       return count;
- }
  static void wacom_wac_finger_report(struct hid_device *hdev,
                struct hid_report *report)
  {
        input_sync(input);
  
        /* keep touch state for pen event */
-       wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(hdev);
+       wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
  }
  
  void wacom_wac_usage_mapping(struct hid_device *hdev,
@@@ -1619,7 -1631,6 +1631,6 @@@ static int wacom_bpt_touch(struct wacom
        struct input_dev *pad_input = wacom->pad_input;
        unsigned char *data = wacom->data;
        int i;
-       int contact_with_no_pen_down_count = 0;
  
        if (data[0] != 0x02)
            return 0;
                        }
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
-                       contact_with_no_pen_down_count++;
                }
        }
  
-       input_mt_report_pointer_emulation(input, true);
+       input_mt_sync_frame(input);
  
        input_report_key(pad_input, BTN_LEFT, (data[1] & 0x08) != 0);
        input_report_key(pad_input, BTN_FORWARD, (data[1] & 0x04) != 0);
        input_report_key(pad_input, BTN_BACK, (data[1] & 0x02) != 0);
        input_report_key(pad_input, BTN_RIGHT, (data[1] & 0x01) != 0);
-       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
  
        return 1;
  }
  
- static int wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data, int last_touch_count)
+ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
  {
        struct wacom_features *features = &wacom->features;
        struct input_dev *input = wacom->input;
        int slot = input_mt_get_slot_by_key(input, data[0]);
  
        if (slot < 0)
-               return 0;
+               return;
  
        touch = touch && !wacom->shared->stylus_in_proximity;
  
                input_report_abs(input, ABS_MT_POSITION_Y, y);
                input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
                input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
-               last_touch_count++;
        }
-       return last_touch_count;
  }
  
  static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
@@@ -1729,7 -1737,6 +1737,6 @@@ static int wacom_bpt3_touch(struct waco
        unsigned char *data = wacom->data;
        int count = data[1] & 0x07;
        int i;
-       int contact_with_no_pen_down_count = 0;
  
        if (data[0] != 0x02)
            return 0;
                int msg_id = data[offset];
  
                if (msg_id >= 2 && msg_id <= 17)
-                       contact_with_no_pen_down_count = 
-                           wacom_bpt3_touch_msg(wacom, data + offset,
-                                                contact_with_no_pen_down_count);
+                       wacom_bpt3_touch_msg(wacom, data + offset);
                else if (msg_id == 128)
                        wacom_bpt3_button_msg(wacom, data + offset);
  
        }
-       input_mt_report_pointer_emulation(input, true);
-       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+       input_mt_sync_frame(input);
+       wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
  
        return 1;
  }
@@@ -1760,23 -1765,9 +1765,9 @@@ static int wacom_bpt_pen(struct wacom_w
        unsigned char *data = wacom->data;
        int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0;
  
-       if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_USB)
+       if (data[0] != WACOM_REPORT_PENABLED)
            return 0;
  
-       if (data[0] == WACOM_REPORT_USB) {
-               if (features->type == INTUOSHT &&
-                   wacom->shared->touch_input &&
-                   features->touch_max) {
-                       input_report_switch(wacom->shared->touch_input,
-                                           SW_MUTE_DEVICE, data[8] & 0x40);
-                       input_sync(wacom->shared->touch_input);
-               }
-               return 0;
-       }
-       if (wacom->shared->touch_down)
-               return 0;
        prox = (data[1] & 0x20) == 0x20;
  
        /*
         *
         * Hardware does report zero in most out-of-prox cases but not all.
         */
-       if (prox) {
-               if (!wacom->shared->stylus_in_proximity) {
-                       if (data[1] & 0x08) {
-                               wacom->tool[0] = BTN_TOOL_RUBBER;
-                               wacom->id[0] = ERASER_DEVICE_ID;
-                       } else {
-                               wacom->tool[0] = BTN_TOOL_PEN;
-                               wacom->id[0] = STYLUS_DEVICE_ID;
-                       }
-                       wacom->shared->stylus_in_proximity = true;
+       if (!wacom->shared->stylus_in_proximity) {
+               if (data[1] & 0x08) {
+                       wacom->tool[0] = BTN_TOOL_RUBBER;
+                       wacom->id[0] = ERASER_DEVICE_ID;
+               } else {
+                       wacom->tool[0] = BTN_TOOL_PEN;
+                       wacom->id[0] = STYLUS_DEVICE_ID;
                }
+       }
+       wacom->shared->stylus_in_proximity = prox;
+       if (wacom->shared->touch_down)
+               return 0;
+       if (prox) {
                x = le16_to_cpup((__le16 *)&data[2]);
                y = le16_to_cpup((__le16 *)&data[4]);
                p = le16_to_cpup((__le16 *)&data[6]);
                pen = data[1] & 0x01;
                btn1 = data[1] & 0x02;
                btn2 = data[1] & 0x04;
+       } else {
+               wacom->id[0] = 0;
        }
  
        input_report_key(input, BTN_TOUCH, pen);
        input_report_abs(input, ABS_PRESSURE, p);
        input_report_abs(input, ABS_DISTANCE, d);
  
-       if (!prox) {
-               wacom->id[0] = 0;
-               wacom->shared->stylus_in_proximity = false;
-       }
        input_report_key(input, wacom->tool[0], prox); /* PEN or RUBBER */
        input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
  
@@@ -1849,6 -1841,91 +1841,91 @@@ static int wacom_bpt_irq(struct wacom_w
        return 0;
  }
  
+ static void wacom_bamboo_pad_pen_event(struct wacom_wac *wacom,
+               unsigned char *data)
+ {
+       unsigned char prefix;
+       /*
+        * We need to reroute the event from the debug interface to the
+        * pen interface.
+        * We need to add the report ID to the actual pen report, so we
+        * temporary overwrite the first byte to prevent having to kzalloc/kfree
+        * and memcpy the report.
+        */
+       prefix = data[0];
+       data[0] = WACOM_REPORT_BPAD_PEN;
+       /*
+        * actually reroute the event.
+        * No need to check if wacom->shared->pen is valid, hid_input_report()
+        * will check for us.
+        */
+       hid_input_report(wacom->shared->pen, HID_INPUT_REPORT, data,
+                        WACOM_PKGLEN_PENABLED, 1);
+       data[0] = prefix;
+ }
+ static int wacom_bamboo_pad_touch_event(struct wacom_wac *wacom,
+               unsigned char *data)
+ {
+       struct input_dev *input = wacom->input;
+       unsigned char *finger_data, prefix;
+       unsigned id;
+       int x, y;
+       bool valid;
+       prefix = data[0];
+       for (id = 0; id < wacom->features.touch_max; id++) {
+               valid = !!(prefix & BIT(id)) &&
+                       !wacom->shared->stylus_in_proximity;
+               input_mt_slot(input, id);
+               input_mt_report_slot_state(input, MT_TOOL_FINGER, valid);
+               if (!valid)
+                       continue;
+               finger_data = data + 1 + id * 3;
+               x = finger_data[0] | ((finger_data[1] & 0x0f) << 8);
+               y = (finger_data[2] << 4) | (finger_data[1] >> 4);
+               input_report_abs(input, ABS_MT_POSITION_X, x);
+               input_report_abs(input, ABS_MT_POSITION_Y, y);
+       }
+       input_mt_sync_frame(input);
+       input_report_key(input, BTN_LEFT, prefix & 0x40);
+       input_report_key(input, BTN_RIGHT, prefix & 0x80);
+       /* keep touch state for pen event */
+       wacom->shared->touch_down = !!prefix &&
+                                   !wacom->shared->stylus_in_proximity;
+       return 1;
+ }
+ static int wacom_bamboo_pad_irq(struct wacom_wac *wacom, size_t len)
+ {
+       unsigned char *data = wacom->data;
+       if (!((len == WACOM_PKGLEN_BPAD_TOUCH) ||
+             (len == WACOM_PKGLEN_BPAD_TOUCH_USB)) ||
+           (data[0] != WACOM_REPORT_BPAD_TOUCH))
+               return 0;
+       if (data[1] & 0x01)
+               wacom_bamboo_pad_pen_event(wacom, &data[1]);
+       if (data[1] & 0x02)
+               return wacom_bamboo_pad_touch_event(wacom, &data[9]);
+       return 0;
+ }
  static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
  {
        unsigned char *data = wacom->data;
  
        connected = data[1] & 0x01;
        if (connected) {
-               int pid, battery, ps_connected;
+               int pid, battery, charging;
  
                if ((wacom->shared->type == INTUOSHT) &&
                    wacom->shared->touch_input &&
  
                pid = get_unaligned_be16(&data[6]);
                battery = (data[5] & 0x3f) * 100 / 31;
-               ps_connected = !!(data[5] & 0x80);
+               charging = !!(data[5] & 0x80);
                if (wacom->pid != pid) {
                        wacom->pid = pid;
                        wacom_schedule_work(wacom);
                }
  
-               if (wacom->shared->type &&
-                   (battery != wacom->battery_capacity ||
-                    ps_connected != wacom->ps_connected)) {
-                       wacom->battery_capacity = battery;
-                       wacom->ps_connected = ps_connected;
-                       wacom->bat_charging = ps_connected &&
-                                               wacom->battery_capacity < 100;
-                       wacom_notify_battery(wacom);
-               }
+               if (wacom->shared->type)
+                       wacom_notify_battery(wacom, battery, charging, 1, 0);
        } else if (wacom->pid != 0) {
                /* disconnected while previously connected */
                wacom->pid = 0;
                wacom_schedule_work(wacom);
-               wacom->battery_capacity = 0;
-               wacom->bat_charging = 0;
-               wacom->ps_connected = 0;
+               wacom_notify_battery(wacom, 0, 0, 0, 0);
+       }
+       return 0;
+ }
+ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
+ {
+       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+       struct wacom_features *features = &wacom_wac->features;
+       unsigned char *data = wacom_wac->data;
+       if (data[0] != WACOM_REPORT_USB)
+               return 0;
+       if (features->type == INTUOSHT &&
+           wacom_wac->shared->touch_input &&
+           features->touch_max) {
+               input_report_switch(wacom_wac->shared->touch_input,
+                                   SW_MUTE_DEVICE, data[8] & 0x40);
+               input_sync(wacom_wac->shared->touch_input);
        }
  
 -              if (!wacom->battery.dev &&
+       if (data[9] & 0x02) { /* wireless module is attached */
+               int battery = (data[8] & 0x3f) * 100 / 31;
+               bool charging = !!(data[8] & 0x80);
+               wacom_notify_battery(wacom_wac, battery, charging,
+                                    battery || charging, 1);
 -               wacom->battery.dev) {
++              if (!wacom->battery &&
+                   !(features->quirks & WACOM_QUIRK_BATTERY)) {
+                       features->quirks |= WACOM_QUIRK_BATTERY;
+                       INIT_WORK(&wacom->work, wacom_battery_work);
+                       wacom_schedule_work(wacom_wac);
+               }
+       }
+       else if ((features->quirks & WACOM_QUIRK_BATTERY) &&
++               wacom->battery) {
+               features->quirks &= ~WACOM_QUIRK_BATTERY;
+               INIT_WORK(&wacom->work, wacom_battery_work);
+               wacom_schedule_work(wacom_wac);
+               wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
+       }
        return 0;
  }
  
@@@ -1967,6 -2077,8 +2077,8 @@@ void wacom_wac_irq(struct wacom_wac *wa
        case INTUOSPL:
                if (len == WACOM_PKGLEN_BBTOUCH3)
                        sync = wacom_bpt3_touch(wacom_wac);
+               else if (wacom_wac->data[0] == WACOM_REPORT_USB)
+                       sync = wacom_status_irq(wacom_wac, len);
                else
                        sync = wacom_intuos_irq(wacom_wac);
                break;
  
        case BAMBOO_PT:
        case INTUOSHT:
-               sync = wacom_bpt_irq(wacom_wac, len);
+               if (wacom_wac->data[0] == WACOM_REPORT_USB)
+                       sync = wacom_status_irq(wacom_wac, len);
+               else
+                       sync = wacom_bpt_irq(wacom_wac, len);
+               break;
+       case BAMBOO_PAD:
+               sync = wacom_bamboo_pad_irq(wacom_wac, len);
                break;
  
        case WIRELESS:
@@@ -2054,12 -2173,6 +2173,6 @@@ void wacom_setup_device_quirks(struct w
                features->y_max = 1023;
        }
  
-       /* these device have multiple inputs */
-       if (features->type >= WIRELESS ||
-           (features->type >= INTUOS5S && features->type <= INTUOSHT) ||
-           (features->oVid && features->oPid))
-               features->quirks |= WACOM_QUIRK_MULTI_INPUT;
        /* quirk for bamboo touch with 2 low res touches */
        if (features->type == BAMBOO_PT &&
            features->pktlen == WACOM_PKGLEN_BBTOUCH) {
@@@ -2323,6 -2436,13 +2436,13 @@@ int wacom_setup_pentouch_input_capabili
                                              0, 0);
                }
                break;
+       case BAMBOO_PAD:
+               __clear_bit(ABS_MISC, input_dev->absbit);
+               input_mt_init_slots(input_dev, features->touch_max,
+                                   INPUT_MT_POINTER);
+               __set_bit(BTN_LEFT, input_dev->keybit);
+               __set_bit(BTN_RIGHT, input_dev->keybit);
+               break;
        }
        return 0;
  }
@@@ -2772,6 -2892,15 +2892,15 @@@ static const struct wacom_features waco
        { "Wacom Cintiq 13HD", 59152, 33448, 1023, 63,
          WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
+ static const struct wacom_features wacom_features_0x333 =
+       { "Wacom Cintiq 13HD touch", 59152, 33448, 2047, 63,
+         WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x335 };
+ static const struct wacom_features wacom_features_0x335 =
+       { "Wacom Cintiq 13HD touch", .type = WACOM_24HDT, /* Touch */
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x333, .touch_max = 10,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
  static const struct wacom_features wacom_features_0xC7 =
        { "Wacom DTU1931", 37832, 30305, 511, 0,
          PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@@ -2976,6 -3105,12 +3105,12 @@@ static const struct wacom_features waco
        { "Wacom ISDv5 30C", .type = WACOM_24HDT, /* Touch */
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30A, .touch_max = 10,
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+ static const struct wacom_features wacom_features_0x318 =
+       { "Wacom USB Bamboo PAD", 4095, 4095, /* Touch */
+         .type = BAMBOO_PAD, 35, 48, .touch_max = 4 };
+ static const struct wacom_features wacom_features_0x319 =
+       { "Wacom Wireless Bamboo PAD", 4095, 4095, /* Touch */
+         .type = BAMBOO_PAD, 35, 48, .touch_max = 4 };
  static const struct wacom_features wacom_features_0x323 =
        { "Wacom Intuos P M", 21600, 13500, 1023, 31,
          INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
@@@ -2992,6 -3127,10 +3127,10 @@@ static const struct wacom_features waco
        HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
        .driver_data = (kernel_ulong_t)&wacom_features_##prod
  
+ #define I2C_DEVICE_WACOM(prod)                                                \
+       HID_DEVICE(BUS_I2C, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
+       .driver_data = (kernel_ulong_t)&wacom_features_##prod
  #define USB_DEVICE_LENOVO(prod)                                       \
        HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, prod),                     \
        .driver_data = (kernel_ulong_t)&wacom_features_##prod
@@@ -3124,11 -3263,15 +3263,15 @@@ const struct hid_device_id wacom_ids[] 
        { USB_DEVICE_WACOM(0x314) },
        { USB_DEVICE_WACOM(0x315) },
        { USB_DEVICE_WACOM(0x317) },
+       { USB_DEVICE_WACOM(0x318) },
+       { USB_DEVICE_WACOM(0x319) },
        { USB_DEVICE_WACOM(0x323) },
        { USB_DEVICE_WACOM(0x32A) },
        { USB_DEVICE_WACOM(0x32B) },
        { USB_DEVICE_WACOM(0x32C) },
        { USB_DEVICE_WACOM(0x32F) },
+       { USB_DEVICE_WACOM(0x333) },
+       { USB_DEVICE_WACOM(0x335) },
        { USB_DEVICE_WACOM(0x4001) },
        { USB_DEVICE_WACOM(0x4004) },
        { USB_DEVICE_WACOM(0x5000) },
        { USB_DEVICE_LENOVO(0x6004) },
  
        { USB_DEVICE_WACOM(HID_ANY_ID) },
+       { I2C_DEVICE_WACOM(HID_ANY_ID) },
        { }
  };
  MODULE_DEVICE_TABLE(hid, wacom_ids);
diff --combined include/linux/hid.h
@@@ -159,6 -159,7 +159,7 @@@ struct hid_item 
  #define HID_UP_LED            0x00080000
  #define HID_UP_BUTTON         0x00090000
  #define HID_UP_ORDINAL                0x000a0000
+ #define HID_UP_TELEPHONY      0x000b0000
  #define HID_UP_CONSUMER               0x000c0000
  #define HID_UP_DIGITIZER      0x000d0000
  #define HID_UP_PID            0x000f0000
  #define HID_DG_DEVICEINDEX    0x000d0053
  #define HID_DG_CONTACTCOUNT   0x000d0054
  #define HID_DG_CONTACTMAX     0x000d0055
+ #define HID_DG_BUTTONTYPE     0x000d0059
  #define HID_DG_BARRELSWITCH2  0x000d005a
  #define HID_DG_TOOLSERIALNUMBER       0x000d005b
  
@@@ -514,10 -516,10 +516,10 @@@ struct hid_device {                                                     /* device rep
  #ifdef CONFIG_HID_BATTERY_STRENGTH
        /*
         * Power supply information for HID devices which report
 -       * battery strength. power_supply is registered iff
 -       * battery.name is non-NULL.
 +       * battery strength. power_supply was successfully registered if
 +       * battery is non-NULL.
         */
 -      struct power_supply battery;
 +      struct power_supply *battery;
        __s32 battery_min;
        __s32 battery_max;
        __s32 battery_report_type;
@@@ -702,6 -702,10 +702,10 @@@ struct input_keymap_entry 
  #define KEY_NUMERIC_9         0x209
  #define KEY_NUMERIC_STAR      0x20a
  #define KEY_NUMERIC_POUND     0x20b
+ #define KEY_NUMERIC_A         0x20c   /* Phone key A - HUT Telephony 0xb9 */
+ #define KEY_NUMERIC_B         0x20d
+ #define KEY_NUMERIC_C         0x20e
+ #define KEY_NUMERIC_D         0x20f
  
  #define KEY_CAMERA_FOCUS      0x210
  #define KEY_WPS_BUTTON                0x211   /* WiFi Protected Setup key */
   */
  #define MT_TOOL_FINGER                0
  #define MT_TOOL_PEN           1
 -#define MT_TOOL_MAX           1
 +#define MT_TOOL_PALM          2
 +#define MT_TOOL_MAX           2
  
  /*
   * Values describing the status of a force-feedback effect