Merge branch 'wacom' into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Thu, 7 Aug 2014 06:31:48 +0000 (23:31 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Thu, 7 Aug 2014 06:31:48 +0000 (23:31 -0700)
Merge large update to Wacom driver, converting it from USB to a HID
driver and unifying wired and bluetooth support, from Benjamin
Tissoires.

drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-core.c
drivers/hid/hid-wacom.c [deleted file]
drivers/hid/wacom.h [moved from drivers/input/tablet/wacom.h with 89% similarity]
drivers/hid/wacom_sys.c [moved from drivers/input/tablet/wacom_sys.c with 51% similarity]
drivers/hid/wacom_wac.c [moved from drivers/input/tablet/wacom_wac.c with 74% similarity]
drivers/hid/wacom_wac.h [moved from drivers/input/tablet/wacom_wac.h with 88% similarity]
drivers/input/tablet/Kconfig
drivers/input/tablet/Makefile
include/linux/hid.h

index 5e79c6ad914f301aa676a763412727987c8610a4..4ed682cd1236610f6b0c7271e239d2ff7addd22a 100644 (file)
@@ -748,12 +748,17 @@ config THRUSTMASTER_FF
          Rumble Force or Force Feedback Wheel.
 
 config HID_WACOM
-       tristate "Wacom Bluetooth devices support"
+       tristate "Wacom Intuos/Graphire tablet support (USB)"
        depends on HID
-       depends on LEDS_CLASS
        select POWER_SUPPLY
-       ---help---
-       Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.
+       select NEW_LEDS
+       select LEDS_CLASS
+       help
+         Say Y here if you want to use the USB or BT version of the Wacom Intuos
+         or Graphire tablet.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wacom.
 
 config HID_WIIMOTE
        tristate "Nintendo Wii / Wii U peripherals"
index a6fa6baf368e49a254ba79646bc29abbd6575519..e38c772ace7611baae42015eef0c9c3d2feec231 100644 (file)
@@ -115,7 +115,9 @@ obj-$(CONFIG_HID_UCLOGIC)   += hid-uclogic.o
 obj-$(CONFIG_HID_XINMO)                += hid-xinmo.o
 obj-$(CONFIG_HID_ZEROPLUS)     += hid-zpff.o
 obj-$(CONFIG_HID_ZYDACRON)     += hid-zydacron.o
-obj-$(CONFIG_HID_WACOM)                += hid-wacom.o
+
+wacom-objs                     := wacom_wac.o wacom_sys.o
+obj-$(CONFIG_HID_WACOM)                += wacom.o
 obj-$(CONFIG_HID_WALTOP)       += hid-waltop.o
 obj-$(CONFIG_HID_WIIMOTE)      += hid-wiimote.o
 obj-$(CONFIG_HID_SENSOR_HUB)   += hid-sensor-hub.o
index 8ed66fd1ea87616416310884de0793d32ffabb6d..b3181ea8f86020adf7a91dec543f82407f27fea9 100644 (file)
@@ -787,6 +787,15 @@ static int hid_scan_report(struct hid_device *hid)
                /* hid-rmi should take care of them, not hid-generic */
                hid->group = HID_GROUP_RMI;
 
+       /*
+        * Vendor specific handlings
+        */
+       switch (hid->vendor) {
+       case USB_VENDOR_ID_WACOM:
+               hid->group = HID_GROUP_WACOM;
+               break;
+       }
+
        vfree(parser);
        return 0;
 }
@@ -1933,8 +1942,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) },
-       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
-       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_Q_PAD) },
@@ -2339,7 +2346,6 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_WACOM, HID_ANY_ID) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
deleted file mode 100644 (file)
index 902013e..0000000
+++ /dev/null
@@ -1,973 +0,0 @@
-/*
- *  Bluetooth Wacom Tablet support
- *
- *  Copyright (c) 1999 Andreas Gal
- *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
- *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
- *  Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
- *  Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
- *  Copyright (c) 2011 Przemys┼éaw Firszt <przemo@firszt.eu>
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/device.h>
-#include <linux/hid.h>
-#include <linux/module.h>
-#include <linux/leds.h>
-#include <linux/slab.h>
-#include <linux/power_supply.h>
-
-#include "hid-ids.h"
-
-#define PAD_DEVICE_ID  0x0F
-
-#define WAC_CMD_LED_CONTROL     0x20
-#define WAC_CMD_ICON_START_STOP     0x21
-#define WAC_CMD_ICON_TRANSFER       0x26
-
-struct wacom_data {
-       __u16 tool;
-       __u16 butstate;
-       __u8 whlstate;
-       __u8 features;
-       __u32 id;
-       __u32 serial;
-       unsigned char high_speed;
-       __u8 battery_capacity;
-       __u8 power_raw;
-       __u8 ps_connected;
-       __u8 bat_charging;
-       struct power_supply battery;
-       struct power_supply ac;
-       __u8 led_selector;
-       struct led_classdev *leds[4];
-};
-
-/*percent of battery capacity for Graphire
-  8th value means AC online and show 100% capacity */
-static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
-/*percent of battery capacity for Intuos4 WL, AC has a separate bit*/
-static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
-
-static enum power_supply_property wacom_battery_props[] = {
-       POWER_SUPPLY_PROP_PRESENT,
-       POWER_SUPPLY_PROP_CAPACITY,
-       POWER_SUPPLY_PROP_SCOPE,
-       POWER_SUPPLY_PROP_STATUS,
-};
-
-static enum power_supply_property wacom_ac_props[] = {
-       POWER_SUPPLY_PROP_PRESENT,
-       POWER_SUPPLY_PROP_ONLINE,
-       POWER_SUPPLY_PROP_SCOPE,
-};
-
-static void wacom_scramble(__u8 *image)
-{
-       __u16 mask;
-       __u16 s1;
-       __u16 s2;
-       __u16 r1 ;
-       __u16 r2 ;
-       __u16 r;
-       __u8 buf[256];
-       int i, w, x, y, z;
-
-       for (x = 0; x < 32; x++) {
-               for (y = 0; y < 8; y++)
-                       buf[(8 * x) + (7 - y)] = image[(8 * x) + y];
-       }
-
-       /* Change 76543210 into GECA6420 as required by Intuos4 WL
-        *        HGFEDCBA      HFDB7531
-        */
-       for (x = 0; x < 4; x++) {
-               for (y = 0; y < 4; y++) {
-                       for (z = 0; z < 8; z++) {
-                               mask = 0x0001;
-                               r1 = 0;
-                               r2 = 0;
-                               i = (x << 6) + (y << 4) + z;
-                               s1 = buf[i];
-                               s2 = buf[i+8];
-                               for (w = 0; w < 8; w++) {
-                                       r1 |= (s1 & mask);
-                                       r2 |= (s2 & mask);
-                                       s1 <<= 1;
-                                       s2 <<= 1;
-                                       mask <<= 2;
-                               }
-                               r = r1 | (r2 << 1);
-                               i = (x << 6) + (y << 4) + (z << 1);
-                               image[i] = 0xFF & r;
-                               image[i+1] = (0xFF00 & r) >> 8;
-                       }
-               }
-       }
-}
-
-static void wacom_set_image(struct hid_device *hdev, const char *image,
-                                               __u8 icon_no)
-{
-       __u8 rep_data[68];
-       __u8 p[256];
-       int ret, i, j;
-
-       for (i = 0; i < 256; i++)
-               p[i] = image[i];
-
-       rep_data[0] = WAC_CMD_ICON_START_STOP;
-       rep_data[1] = 0;
-       ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
-                                HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
-       if (ret < 0)
-               goto err;
-
-       rep_data[0] = WAC_CMD_ICON_TRANSFER;
-       rep_data[1] = icon_no & 0x07;
-
-       wacom_scramble(p);
-
-       for (i = 0; i < 4; i++) {
-               for (j = 0; j < 64; j++)
-                       rep_data[j + 3] = p[(i << 6) + j];
-
-               rep_data[2] = i;
-               ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 67,
-                                       HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
-       }
-
-       rep_data[0] = WAC_CMD_ICON_START_STOP;
-       rep_data[1] = 0;
-
-       ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
-                                HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
-
-err:
-       return;
-}
-
-static void wacom_leds_set_brightness(struct led_classdev *led_dev,
-                                               enum led_brightness value)
-{
-       struct device *dev = led_dev->dev->parent;
-       struct hid_device *hdev;
-       struct wacom_data *wdata;
-       unsigned char *buf;
-       __u8 led = 0;
-       int i;
-
-       hdev = container_of(dev, struct hid_device, dev);
-       wdata = hid_get_drvdata(hdev);
-       for (i = 0; i < 4; ++i) {
-               if (wdata->leds[i] == led_dev)
-                       wdata->led_selector = i;
-       }
-
-       led = wdata->led_selector | 0x04;
-       buf = kzalloc(9, GFP_KERNEL);
-       if (buf) {
-               buf[0] = WAC_CMD_LED_CONTROL;
-               buf[1] = led;
-               buf[2] = value >> 2;
-               buf[3] = value;
-               /* use fixed brightness for OLEDs */
-               buf[4] = 0x08;
-               hid_hw_raw_request(hdev, buf[0], buf, 9, HID_FEATURE_REPORT,
-                                  HID_REQ_SET_REPORT);
-               kfree(buf);
-       }
-
-       return;
-}
-
-static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev)
-{
-       struct wacom_data *wdata;
-       struct device *dev = led_dev->dev->parent;
-       int value = 0;
-       int i;
-
-       wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
-
-       for (i = 0; i < 4; ++i) {
-               if (wdata->leds[i] == led_dev) {
-                       value = wdata->leds[i]->brightness;
-                       break;
-               }
-       }
-
-       return value;
-}
-
-
-static int wacom_initialize_leds(struct hid_device *hdev)
-{
-       struct wacom_data *wdata = hid_get_drvdata(hdev);
-       struct led_classdev *led;
-       struct device *dev = &hdev->dev;
-       size_t namesz = strlen(dev_name(dev)) + 12;
-       char *name;
-       int i, ret;
-
-       wdata->led_selector = 0;
-
-       for (i = 0; i < 4; i++) {
-               led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
-               if (!led) {
-                       hid_warn(hdev,
-                                "can't allocate memory for LED selector\n");
-                       ret = -ENOMEM;
-                       goto err;
-               }
-
-               name = (void *)&led[1];
-               snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i);
-               led->name = name;
-               led->brightness = 0;
-               led->max_brightness = 127;
-               led->brightness_get = wacom_leds_get_brightness;
-               led->brightness_set = wacom_leds_set_brightness;
-
-               wdata->leds[i] = led;
-
-               ret = led_classdev_register(dev, wdata->leds[i]);
-
-               if (ret) {
-                       wdata->leds[i] = NULL;
-                       kfree(led);
-                       hid_warn(hdev, "can't register LED\n");
-                       goto err;
-               }
-       }
-
-err:
-       return ret;
-}
-
-static void wacom_destroy_leds(struct hid_device *hdev)
-{
-       struct wacom_data *wdata = hid_get_drvdata(hdev);
-       struct led_classdev *led;
-       int i;
-
-       for (i = 0; i < 4; ++i) {
-               if (wdata->leds[i]) {
-                       led = wdata->leds[i];
-                       wdata->leds[i] = NULL;
-                       led_classdev_unregister(led);
-                       kfree(led);
-               }
-       }
-
-}
-
-static int wacom_battery_get_property(struct power_supply *psy,
-                               enum power_supply_property psp,
-                               union power_supply_propval *val)
-{
-       struct wacom_data *wdata = container_of(psy,
-                                       struct wacom_data, battery);
-       int ret = 0;
-
-       switch (psp) {
-       case POWER_SUPPLY_PROP_PRESENT:
-               val->intval = 1;
-               break;
-       case POWER_SUPPLY_PROP_SCOPE:
-               val->intval = POWER_SUPPLY_SCOPE_DEVICE;
-               break;
-       case POWER_SUPPLY_PROP_CAPACITY:
-               val->intval = wdata->battery_capacity;
-               break;
-       case POWER_SUPPLY_PROP_STATUS:
-               if (wdata->bat_charging)
-                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
-               else
-                       if (wdata->battery_capacity == 100 && wdata->ps_connected)
-                               val->intval = POWER_SUPPLY_STATUS_FULL;
-                       else
-                               val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-       return ret;
-}
-
-static int wacom_ac_get_property(struct power_supply *psy,
-                               enum power_supply_property psp,
-                               union power_supply_propval *val)
-{
-       struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
-       int ret = 0;
-
-       switch (psp) {
-       case POWER_SUPPLY_PROP_PRESENT:
-               /* fall through */
-       case POWER_SUPPLY_PROP_ONLINE:
-               val->intval = wdata->ps_connected;
-               break;
-       case POWER_SUPPLY_PROP_SCOPE:
-               val->intval = POWER_SUPPLY_SCOPE_DEVICE;
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-       return ret;
-}
-
-static void wacom_set_features(struct hid_device *hdev, u8 speed)
-{
-       struct wacom_data *wdata = hid_get_drvdata(hdev);
-       int limit, ret;
-       __u8 rep_data[2];
-
-       switch (hdev->product) {
-       case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
-               rep_data[0] = 0x03 ; rep_data[1] = 0x00;
-               limit = 3;
-               do {
-                       ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
-                                       HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
-               } while (ret < 0 && limit-- > 0);
-
-               if (ret >= 0) {
-                       if (speed == 0)
-                               rep_data[0] = 0x05;
-                       else
-                               rep_data[0] = 0x06;
-
-                       rep_data[1] = 0x00;
-                       limit = 3;
-                       do {
-                               ret = hid_hw_raw_request(hdev, rep_data[0],
-                                       rep_data, 2, HID_FEATURE_REPORT,
-                                       HID_REQ_SET_REPORT);
-                       } while (ret < 0 && limit-- > 0);
-
-                       if (ret >= 0) {
-                               wdata->high_speed = speed;
-                               return;
-                       }
-               }
-
-               /*
-                * Note that if the raw queries fail, it's not a hard failure
-                * and it is safe to continue
-                */
-               hid_warn(hdev, "failed to poke device, command %d, err %d\n",
-                        rep_data[0], ret);
-               break;
-       case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
-               if (speed == 1)
-                       wdata->features &= ~0x20;
-               else
-                       wdata->features |= 0x20;
-
-               rep_data[0] = 0x03;
-               rep_data[1] = wdata->features;
-
-               ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
-                               HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
-               if (ret >= 0)
-                       wdata->high_speed = speed;
-               break;
-       }
-
-       return;
-}
-
-static ssize_t wacom_show_speed(struct device *dev,
-                               struct device_attribute
-                               *attr, char *buf)
-{
-       struct wacom_data *wdata = dev_get_drvdata(dev);
-
-       return snprintf(buf, PAGE_SIZE, "%i\n", wdata->high_speed);
-}
-
-static ssize_t wacom_store_speed(struct device *dev,
-                               struct device_attribute *attr,
-                               const char *buf, size_t count)
-{
-       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
-       int new_speed;
-
-       if (sscanf(buf, "%1d", &new_speed ) != 1)
-               return -EINVAL;
-
-       if (new_speed == 0 || new_speed == 1) {
-               wacom_set_features(hdev, new_speed);
-               return strnlen(buf, PAGE_SIZE);
-       } else
-               return -EINVAL;
-}
-
-static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
-               wacom_show_speed, wacom_store_speed);
-
-#define WACOM_STORE(OLED_ID)                                           \
-static ssize_t wacom_oled##OLED_ID##_store(struct device *dev,         \
-                               struct device_attribute *attr,          \
-                               const char *buf, size_t count)          \
-{                                                                      \
-       struct hid_device *hdev = container_of(dev, struct hid_device,  \
-                               dev);                                   \
-                                                                       \
-       if (count != 256)                                               \
-               return -EINVAL;                                         \
-                                                                       \
-       wacom_set_image(hdev, buf, OLED_ID);                            \
-                                                                       \
-       return count;                                                   \
-}                                                                      \
-                                                                       \
-static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL,       \
-                               wacom_oled##OLED_ID##_store)
-
-WACOM_STORE(0);
-WACOM_STORE(1);
-WACOM_STORE(2);
-WACOM_STORE(3);
-WACOM_STORE(4);
-WACOM_STORE(5);
-WACOM_STORE(6);
-WACOM_STORE(7);
-
-static int wacom_gr_parse_report(struct hid_device *hdev,
-                       struct wacom_data *wdata,
-                       struct input_dev *input, unsigned char *data)
-{
-       int tool, x, y, rw;
-
-       tool = 0;
-       /* Get X & Y positions */
-       x = le16_to_cpu(*(__le16 *) &data[2]);
-       y = le16_to_cpu(*(__le16 *) &data[4]);
-
-       /* Get current tool identifier */
-       if (data[1] & 0x90) { /* If pen is in the in/active area */
-               switch ((data[1] >> 5) & 3) {
-               case 0: /* Pen */
-                       tool = BTN_TOOL_PEN;
-                       break;
-
-               case 1: /* Rubber */
-                       tool = BTN_TOOL_RUBBER;
-                       break;
-
-               case 2: /* Mouse with wheel */
-               case 3: /* Mouse without wheel */
-                       tool = BTN_TOOL_MOUSE;
-                       break;
-               }
-
-               /* Reset tool if out of active tablet area */
-               if (!(data[1] & 0x10))
-                       tool = 0;
-       }
-
-       /* If tool changed, notify input subsystem */
-       if (wdata->tool != tool) {
-               if (wdata->tool) {
-                       /* Completely reset old tool state */
-                       if (wdata->tool == BTN_TOOL_MOUSE) {
-                               input_report_key(input, BTN_LEFT, 0);
-                               input_report_key(input, BTN_RIGHT, 0);
-                               input_report_key(input, BTN_MIDDLE, 0);
-                               input_report_abs(input, ABS_DISTANCE,
-                                       input_abs_get_max(input, ABS_DISTANCE));
-                       } else {
-                               input_report_key(input, BTN_TOUCH, 0);
-                               input_report_key(input, BTN_STYLUS, 0);
-                               input_report_key(input, BTN_STYLUS2, 0);
-                               input_report_abs(input, ABS_PRESSURE, 0);
-                       }
-                       input_report_key(input, wdata->tool, 0);
-                       input_sync(input);
-               }
-               wdata->tool = tool;
-               if (tool)
-                       input_report_key(input, tool, 1);
-       }
-
-       if (tool) {
-               input_report_abs(input, ABS_X, x);
-               input_report_abs(input, ABS_Y, y);
-
-               switch ((data[1] >> 5) & 3) {
-               case 2: /* Mouse with wheel */
-                       input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
-                       rw = (data[6] & 0x01) ? -1 :
-                               (data[6] & 0x02) ? 1 : 0;
-                       input_report_rel(input, REL_WHEEL, rw);
-                       /* fall through */
-
-               case 3: /* Mouse without wheel */
-                       input_report_key(input, BTN_LEFT, data[1] & 0x01);
-                       input_report_key(input, BTN_RIGHT, data[1] & 0x02);
-                       /* Compute distance between mouse and tablet */
-                       rw = 44 - (data[6] >> 2);
-                       if (rw < 0)
-                               rw = 0;
-                       else if (rw > 31)
-                               rw = 31;
-                       input_report_abs(input, ABS_DISTANCE, rw);
-                       break;
-
-               default:
-                       input_report_abs(input, ABS_PRESSURE,
-                                       data[6] | (((__u16) (data[1] & 0x08)) << 5));
-                       input_report_key(input, BTN_TOUCH, data[1] & 0x01);
-                       input_report_key(input, BTN_STYLUS, data[1] & 0x02);
-                       input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
-                       break;
-               }
-
-               input_sync(input);
-       }
-
-       /* Report the state of the two buttons at the top of the tablet
-        * as two extra fingerpad keys (buttons 4 & 5). */
-       rw = data[7] & 0x03;
-       if (rw != wdata->butstate) {
-               wdata->butstate = rw;
-               input_report_key(input, BTN_0, rw & 0x02);
-               input_report_key(input, BTN_1, rw & 0x01);
-               input_report_key(input, BTN_TOOL_FINGER, 0xf0);
-               input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
-               input_sync(input);
-       }
-
-       /* Store current battery capacity and power supply state*/
-       rw = (data[7] >> 2 & 0x07);
-       if (rw != wdata->power_raw) {
-               wdata->power_raw = rw;
-               wdata->battery_capacity = batcap_gr[rw];
-               if (rw == 7)
-                       wdata->ps_connected = 1;
-               else
-                       wdata->ps_connected = 0;
-       }
-       return 1;
-}
-
-static void wacom_i4_parse_button_report(struct wacom_data *wdata,
-                       struct input_dev *input, unsigned char *data)
-{
-       __u16 new_butstate;
-       __u8 new_whlstate;
-       __u8 sync = 0;
-
-       new_whlstate = data[1];
-       if (new_whlstate != wdata->whlstate) {
-               wdata->whlstate = new_whlstate;
-               if (new_whlstate & 0x80) {
-                       input_report_key(input, BTN_TOUCH, 1);
-                       input_report_abs(input, ABS_WHEEL, (new_whlstate & 0x7f));
-                       input_report_key(input, BTN_TOOL_FINGER, 1);
-               } else {
-                       input_report_key(input, BTN_TOUCH, 0);
-                       input_report_abs(input, ABS_WHEEL, 0);
-                       input_report_key(input, BTN_TOOL_FINGER, 0);
-               }
-               sync = 1;
-       }
-
-       new_butstate = (data[3] << 1) | (data[2] & 0x01);
-       if (new_butstate != wdata->butstate) {
-               wdata->butstate = new_butstate;
-               input_report_key(input, BTN_0, new_butstate & 0x001);
-               input_report_key(input, BTN_1, new_butstate & 0x002);
-               input_report_key(input, BTN_2, new_butstate & 0x004);
-               input_report_key(input, BTN_3, new_butstate & 0x008);
-               input_report_key(input, BTN_4, new_butstate & 0x010);
-               input_report_key(input, BTN_5, new_butstate & 0x020);
-               input_report_key(input, BTN_6, new_butstate & 0x040);
-               input_report_key(input, BTN_7, new_butstate & 0x080);
-               input_report_key(input, BTN_8, new_butstate & 0x100);
-               input_report_key(input, BTN_TOOL_FINGER, 1);
-               sync = 1;
-       }
-
-       if (sync) {
-               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-               input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
-               input_sync(input);
-       }
-}
-
-static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
-                       struct input_dev *input, unsigned char *data)
-{
-       __u16 x, y, pressure;
-       __u8 distance;
-       __u8 tilt_x, tilt_y;
-
-       switch (data[1]) {
-       case 0x80: /* Out of proximity report */
-               input_report_key(input, BTN_TOUCH, 0);
-               input_report_abs(input, ABS_PRESSURE, 0);
-               input_report_key(input, BTN_STYLUS, 0);
-               input_report_key(input, BTN_STYLUS2, 0);
-               input_report_key(input, wdata->tool, 0);
-               input_report_abs(input, ABS_MISC, 0);
-               input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
-               wdata->tool = 0;
-               input_sync(input);
-               break;
-       case 0xC2: /* Tool report */
-               wdata->id = ((data[2] << 4) | (data[3] >> 4) |
-                       ((data[7] & 0x0f) << 20) |
-                       ((data[8] & 0xf0) << 12));
-               wdata->serial = ((data[3] & 0x0f) << 28) +
-                               (data[4] << 20) + (data[5] << 12) +
-                               (data[6] << 4) + (data[7] >> 4);
-
-               switch (wdata->id) {
-               case 0x100802:
-                       wdata->tool = BTN_TOOL_PEN;
-                       break;
-               case 0x10080A:
-                       wdata->tool = BTN_TOOL_RUBBER;
-                       break;
-               }
-               break;
-       default: /* Position/pressure report */
-               x = data[2] << 9 | data[3] << 1 | ((data[9] & 0x02) >> 1);
-               y = data[4] << 9 | data[5] << 1 | (data[9] & 0x01);
-               pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5)
-                       | (data[1] & 0x01);
-               distance = (data[9] >> 2) & 0x3f;
-               tilt_x = ((data[7] << 1) & 0x7e) | (data[8] >> 7);
-               tilt_y = data[8] & 0x7f;
-
-               input_report_key(input, BTN_TOUCH, pressure > 1);
-
-               input_report_key(input, BTN_STYLUS, data[1] & 0x02);
-               input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
-               input_report_key(input, wdata->tool, 1);
-               input_report_abs(input, ABS_X, x);
-               input_report_abs(input, ABS_Y, y);
-               input_report_abs(input, ABS_PRESSURE, pressure);
-               input_report_abs(input, ABS_DISTANCE, distance);
-               input_report_abs(input, ABS_TILT_X, tilt_x);
-               input_report_abs(input, ABS_TILT_Y, tilt_y);
-               input_report_abs(input, ABS_MISC, wdata->id);
-               input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
-               input_report_key(input, wdata->tool, 1);
-               input_sync(input);
-               break;
-       }
-
-       return;
-}
-
-static void wacom_i4_parse_report(struct hid_device *hdev,
-                       struct wacom_data *wdata,
-                       struct input_dev *input, unsigned char *data)
-{
-       switch (data[0]) {
-       case 0x00: /* Empty report */
-               break;
-       case 0x02: /* Pen report */
-               wacom_i4_parse_pen_report(wdata, input, data);
-               break;
-       case 0x03: /* Features Report */
-               wdata->features = data[2];
-               break;
-       case 0x0C: /* Button report */
-               wacom_i4_parse_button_report(wdata, input, data);
-               break;
-       default:
-               hid_err(hdev, "Unknown report: %d,%d\n", data[0], data[1]);
-               break;
-       }
-}
-
-static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
-               u8 *raw_data, int size)
-{
-       struct wacom_data *wdata = hid_get_drvdata(hdev);
-       struct hid_input *hidinput;
-       struct input_dev *input;
-       unsigned char *data = (unsigned char *) raw_data;
-       int i;
-       __u8 power_raw;
-
-       if (!(hdev->claimed & HID_CLAIMED_INPUT))
-               return 0;
-
-       hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
-       input = hidinput->input;
-
-       switch (hdev->product) {
-       case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
-               if (data[0] == 0x03) {
-                       return wacom_gr_parse_report(hdev, wdata, input, data);
-               } else {
-                       hid_err(hdev, "Unknown report: %d,%d size:%d\n",
-                                       data[0], data[1], size);
-                       return 0;
-               }
-               break;
-       case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
-               i = 1;
-
-               switch (data[0]) {
-               case 0x04:
-                       wacom_i4_parse_report(hdev, wdata, input, data + i);
-                       i += 10;
-                       /* fall through */
-               case 0x03:
-                       wacom_i4_parse_report(hdev, wdata, input, data + i);
-                       i += 10;
-                       wacom_i4_parse_report(hdev, wdata, input, data + i);
-                       power_raw = data[i+10];
-                       if (power_raw != wdata->power_raw) {
-                               wdata->power_raw = power_raw;
-                               wdata->battery_capacity = batcap_i4[power_raw & 0x07];
-                               wdata->bat_charging = (power_raw & 0x08) ? 1 : 0;
-                               wdata->ps_connected = (power_raw & 0x10) ? 1 : 0;
-                       }
-
-                       break;
-               default:
-                       hid_err(hdev, "Unknown report: %d,%d size:%d\n",
-                                       data[0], data[1], size);
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
-       struct hid_field *field, struct hid_usage *usage, unsigned long **bit,
-                                                               int *max)
-{
-       struct input_dev *input = hi->input;
-
-       __set_bit(INPUT_PROP_POINTER, input->propbit);
-
-       /* Basics */
-       input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
-
-       __set_bit(REL_WHEEL, input->relbit);
-
-       __set_bit(BTN_TOOL_PEN, input->keybit);
-       __set_bit(BTN_TOUCH, input->keybit);
-       __set_bit(BTN_STYLUS, input->keybit);
-       __set_bit(BTN_STYLUS2, input->keybit);
-       __set_bit(BTN_LEFT, input->keybit);
-       __set_bit(BTN_RIGHT, input->keybit);
-       __set_bit(BTN_MIDDLE, input->keybit);
-
-       /* Pad */
-       input_set_capability(input, EV_MSC, MSC_SERIAL);
-
-       __set_bit(BTN_0, input->keybit);
-       __set_bit(BTN_1, input->keybit);
-       __set_bit(BTN_TOOL_FINGER, input->keybit);
-
-       /* Distance, rubber and mouse */
-       __set_bit(BTN_TOOL_RUBBER, input->keybit);
-       __set_bit(BTN_TOOL_MOUSE, input->keybit);
-
-       switch (hdev->product) {
-       case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
-               input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
-               input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
-               input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
-               input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);
-               break;
-       case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
-               __set_bit(ABS_WHEEL, input->absbit);
-               __set_bit(ABS_MISC, input->absbit);
-               __set_bit(BTN_2, input->keybit);
-               __set_bit(BTN_3, input->keybit);
-               __set_bit(BTN_4, input->keybit);
-               __set_bit(BTN_5, input->keybit);
-               __set_bit(BTN_6, input->keybit);
-               __set_bit(BTN_7, input->keybit);
-               __set_bit(BTN_8, input->keybit);
-               input_set_abs_params(input, ABS_WHEEL, 0, 71, 0, 0);
-               input_set_abs_params(input, ABS_X, 0, 40640, 4, 0);
-               input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0);
-               input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0);
-               input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0);
-               input_set_abs_params(input, ABS_TILT_X, 0, 127, 0, 0);
-               input_set_abs_params(input, ABS_TILT_Y, 0, 127, 0, 0);
-               break;
-       }
-
-       return 0;
-}
-
-static int wacom_probe(struct hid_device *hdev,
-               const struct hid_device_id *id)
-{
-       struct wacom_data *wdata;
-       int ret;
-
-       wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
-       if (wdata == NULL) {
-               hid_err(hdev, "can't alloc wacom descriptor\n");
-               return -ENOMEM;
-       }
-
-       hid_set_drvdata(hdev, wdata);
-
-       /* Parse the HID report now */
-       ret = hid_parse(hdev);
-       if (ret) {
-               hid_err(hdev, "parse failed\n");
-               goto err_free;
-       }
-
-       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-       if (ret) {
-               hid_err(hdev, "hw start failed\n");
-               goto err_free;
-       }
-
-       ret = device_create_file(&hdev->dev, &dev_attr_speed);
-       if (ret)
-               hid_warn(hdev,
-                        "can't create sysfs speed attribute err: %d\n", ret);
-
-#define OLED_INIT(OLED_ID)                                             \
-       do {                                                            \
-               ret = device_create_file(&hdev->dev,                    \
-                               &dev_attr_oled##OLED_ID##_img);         \
-               if (ret)                                                \
-                       hid_warn(hdev,                                  \
-                        "can't create sysfs oled attribute, err: %d\n", ret);\
-       } while (0)
-
-OLED_INIT(0);
-OLED_INIT(1);
-OLED_INIT(2);
-OLED_INIT(3);
-OLED_INIT(4);
-OLED_INIT(5);
-OLED_INIT(6);
-OLED_INIT(7);
-
-       wdata->features = 0;
-       wacom_set_features(hdev, 1);
-
-       if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) {
-               sprintf(hdev->name, "%s", "Wacom Intuos4 WL");
-               ret = wacom_initialize_leds(hdev);
-               if (ret)
-                       hid_warn(hdev,
-                                "can't create led attribute, err: %d\n", ret);
-       }
-
-       wdata->battery.properties = wacom_battery_props;
-       wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
-       wdata->battery.get_property = wacom_battery_get_property;
-       wdata->battery.name = "wacom_battery";
-       wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
-       wdata->battery.use_for_apm = 0;
-
-
-       ret = power_supply_register(&hdev->dev, &wdata->battery);
-       if (ret) {
-               hid_err(hdev, "can't create sysfs battery attribute, err: %d\n",
-                       ret);
-               goto err_battery;
-       }
-
-       power_supply_powers(&wdata->battery, &hdev->dev);
-
-       wdata->ac.properties = wacom_ac_props;
-       wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
-       wdata->ac.get_property = wacom_ac_get_property;
-       wdata->ac.name = "wacom_ac";
-       wdata->ac.type = POWER_SUPPLY_TYPE_MAINS;
-       wdata->ac.use_for_apm = 0;
-
-       ret = power_supply_register(&hdev->dev, &wdata->ac);
-       if (ret) {
-               hid_err(hdev,
-                       "can't create ac battery attribute, err: %d\n", ret);
-               goto err_ac;
-       }
-
-       power_supply_powers(&wdata->ac, &hdev->dev);
-       return 0;
-
-err_ac:
-       power_supply_unregister(&wdata->battery);
-err_battery:
-       wacom_destroy_leds(hdev);
-       device_remove_file(&hdev->dev, &dev_attr_oled0_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled1_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled2_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled3_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled4_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled5_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled6_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled7_img);
-       device_remove_file(&hdev->dev, &dev_attr_speed);
-       hid_hw_stop(hdev);
-err_free:
-       kfree(wdata);
-       return ret;
-}
-
-static void wacom_remove(struct hid_device *hdev)
-{
-       struct wacom_data *wdata = hid_get_drvdata(hdev);
-
-       wacom_destroy_leds(hdev);
-       device_remove_file(&hdev->dev, &dev_attr_oled0_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled1_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled2_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled3_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled4_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled5_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled6_img);
-       device_remove_file(&hdev->dev, &dev_attr_oled7_img);
-       device_remove_file(&hdev->dev, &dev_attr_speed);
-       hid_hw_stop(hdev);
-
-       power_supply_unregister(&wdata->battery);
-       power_supply_unregister(&wdata->ac);
-       kfree(hid_get_drvdata(hdev));
-}
-
-static const struct hid_device_id wacom_devices[] = {
-       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
-       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
-
-       { }
-};
-MODULE_DEVICE_TABLE(hid, wacom_devices);
-
-static struct hid_driver wacom_driver = {
-       .name = "wacom",
-       .id_table = wacom_devices,
-       .probe = wacom_probe,
-       .remove = wacom_remove,
-       .raw_event = wacom_raw_event,
-       .input_mapped = wacom_input_mapped,
-};
-module_hid_driver(wacom_driver);
-
-MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL");
-MODULE_LICENSE("GPL");
similarity index 89%
rename from drivers/input/tablet/wacom.h
rename to drivers/hid/wacom.h
index 9ebf0ed3b3b372e6822e69b6f3efd68403a3c31a..64bc1b296d91ed2ac5dd1121c95c49c2eb676ce1 100644 (file)
@@ -12,6 +12,7 @@
  *  Copyright (c) 2001 Frederic Lepied         <flepied@mandrakesoft.com>
  *  Copyright (c) 2004 Panagiotis Issaris      <panagiotis.issaris@mech.kuleuven.ac.be>
  *  Copyright (c) 2002-2011 Ping Cheng         <pingc@wacom.com>
+ *  Copyright (c) 2014 Benjamin Tissoires      <benjamin.tissoires@redhat.com>
  *
  *  ChangeLog:
  *      v0.1 (vp)  - Initial release
@@ -72,6 +73,8 @@
  *      v1.52 (pc) - Query Wacom data upon system resume
  *                 - add defines for features->type
  *                 - add new devices (0x9F, 0xE2, and 0XE3)
+ *      v2.00 (bt) - conversion to a HID driver
+ *                 - integration of the Bluetooth devices
  */
 
 /*
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.53"
+#define DRIVER_VERSION "v2.00"
 #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 #define DRIVER_DESC "USB Wacom tablet driver"
 #define DRIVER_LICENSE "GPL"
 
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-
 #define USB_VENDOR_ID_WACOM    0x056a
 #define USB_VENDOR_ID_LENOVO   0x17ef
 
 struct wacom {
-       dma_addr_t data_dma;
        struct usb_device *usbdev;
        struct usb_interface *intf;
-       struct urb *irq;
        struct wacom_wac wacom_wac;
+       struct hid_device *hdev;
        struct mutex lock;
        struct work_struct work;
-       bool open;
-       char phys[32];
        struct wacom_led {
                u8 select[2]; /* status led selector (0..3) */
                u8 llv;       /* status led brightness no button (1..127) */
                u8 hlv;       /* status led brightness button pressed (1..127) */
                u8 img_lum;   /* OLED matrix display brightness */
        } led;
+       bool led_initialized;
        struct power_supply battery;
+       struct power_supply ac;
 };
 
 static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
@@ -130,10 +128,19 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
        schedule_work(&wacom->work);
 }
 
-extern const struct usb_device_id wacom_ids[];
+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);
 void wacom_setup_device_quirks(struct wacom_features *features);
 int wacom_setup_input_capabilities(struct input_dev *input_dev,
                                   struct wacom_wac *wacom_wac);
+int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
+                                      struct wacom_wac *wacom_wac);
 #endif
similarity index 51%
rename from drivers/input/tablet/wacom_sys.c
rename to drivers/hid/wacom_sys.c
index 2c613cd41dd68260b345141489c7c06defd94f89..3e388ec31da84bd5d41b9c6d6771d75ceb2c81a2 100644 (file)
 
 #include "wacom_wac.h"
 #include "wacom.h"
+#include <linux/hid.h>
 
-/* defines to get HID report descriptor */
-#define HID_DEVICET_HID                (USB_TYPE_CLASS | 0x01)
-#define HID_DEVICET_REPORT     (USB_TYPE_CLASS | 0x02)
-#define HID_USAGE_UNDEFINED            0x00
-#define HID_USAGE_PAGE                 0x05
-#define HID_USAGE_PAGE_DIGITIZER       0x0d
-#define HID_USAGE_PAGE_DESKTOP         0x01
-#define HID_USAGE                      0x09
-#define HID_USAGE_X                    ((HID_USAGE_PAGE_DESKTOP << 16) | 0x30)
-#define HID_USAGE_Y                    ((HID_USAGE_PAGE_DESKTOP << 16) | 0x31)
-#define HID_USAGE_PRESSURE             ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x30)
-#define HID_USAGE_X_TILT               ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x3d)
-#define HID_USAGE_Y_TILT               ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x3e)
-#define HID_USAGE_FINGER               ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x22)
-#define HID_USAGE_STYLUS               ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x20)
-#define HID_USAGE_CONTACTMAX           ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x55)
-#define HID_COLLECTION                 0xa1
-#define HID_COLLECTION_LOGICAL         0x02
-#define HID_COLLECTION_END             0xc0
-
-struct hid_descriptor {
-       struct usb_descriptor_header header;
-       __le16   bcdHID;
-       u8       bCountryCode;
-       u8       bNumDescriptors;
-       u8       bDescriptorType;
-       __le16   wDescriptorLength;
-} __attribute__ ((packed));
-
-/* defines to get/set USB message */
-#define USB_REQ_GET_REPORT     0x01
-#define USB_REQ_SET_REPORT     0x09
-
-#define WAC_HID_FEATURE_REPORT 0x03
 #define WAC_MSG_RETRIES                5
 
 #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
 
-static int wacom_get_report(struct usb_interface *intf, u8 type, u8 id,
+static int wacom_get_report(struct hid_device *hdev, u8 type, u8 id,
                            void *buf, size_t size, unsigned int retries)
 {
-       struct usb_device *dev = interface_to_usbdev(intf);
        int retval;
 
        do {
-               retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-                               USB_REQ_GET_REPORT,
-                               USB_DIR_IN | USB_TYPE_CLASS |
-                               USB_RECIP_INTERFACE,
-                               (type << 8) + id,
-                               intf->altsetting[0].desc.bInterfaceNumber,
-                               buf, size, 100);
+               retval = hid_hw_raw_request(hdev, id, buf, size, type,
+                               HID_REQ_GET_REPORT);
        } while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
 
        return retval;
 }
 
-static int wacom_set_report(struct usb_interface *intf, u8 type, u8 id,
-                           void *buf, size_t size, unsigned int retries)
+static int wacom_set_report(struct hid_device *hdev, u8 type, u8 *buf,
+                           size_t size, unsigned int retries)
 {
-       struct usb_device *dev = interface_to_usbdev(intf);
        int retval;
 
        do {
-               retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                               USB_REQ_SET_REPORT,
-                               USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                               (type << 8) + id,
-                               intf->altsetting[0].desc.bInterfaceNumber,
-                               buf, size, 1000);
+               retval = hid_hw_raw_request(hdev, buf[0], buf, size, type,
+                               HID_REQ_SET_REPORT);
        } while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
 
        return retval;
 }
 
-static void wacom_sys_irq(struct urb *urb)
+static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
+               u8 *raw_data, int size)
 {
-       struct wacom *wacom = urb->context;
-       struct device *dev = &wacom->intf->dev;
-       int retval;
+       struct wacom *wacom = hid_get_drvdata(hdev);
 
-       switch (urb->status) {
-       case 0:
-               /* success */
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               /* this urb is terminated, clean up */
-               dev_dbg(dev, "%s - urb shutting down with status: %d\n",
-                       __func__, urb->status);
-               return;
-       default:
-               dev_dbg(dev, "%s - nonzero urb status received: %d\n",
-                       __func__, urb->status);
-               goto exit;
-       }
+       if (size > WACOM_PKGLEN_MAX)
+               return 1;
+
+       memcpy(wacom->wacom_wac.data, raw_data, size);
 
-       wacom_wac_irq(&wacom->wacom_wac, urb->actual_length);
+       wacom_wac_irq(&wacom->wacom_wac, size);
 
- exit:
-       usb_mark_last_busy(wacom->usbdev);
-       retval = usb_submit_urb(urb, GFP_ATOMIC);
-       if (retval)
-               dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
-                       __func__, retval);
+       return 0;
 }
 
 static int wacom_open(struct input_dev *dev)
 {
        struct wacom *wacom = input_get_drvdata(dev);
-       int retval = 0;
-
-       if (usb_autopm_get_interface(wacom->intf) < 0)
-               return -EIO;
+       int retval;
 
        mutex_lock(&wacom->lock);
-
-       if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
-               retval = -EIO;
-               goto out;
-       }
-
-       wacom->open = true;
-       wacom->intf->needs_remote_wakeup = 1;
-
-out:
+       retval = hid_hw_open(wacom->hdev);
        mutex_unlock(&wacom->lock);
-       usb_autopm_put_interface(wacom->intf);
+
        return retval;
 }
 
 static void wacom_close(struct input_dev *dev)
 {
        struct wacom *wacom = input_get_drvdata(dev);
-       int autopm_error;
-
-       autopm_error = usb_autopm_get_interface(wacom->intf);
 
        mutex_lock(&wacom->lock);
-       usb_kill_urb(wacom->irq);
-       wacom->open = false;
-       wacom->intf->needs_remote_wakeup = 0;
+       hid_hw_close(wacom->hdev);
        mutex_unlock(&wacom->lock);
-
-       if (!autopm_error)
-               usb_autopm_put_interface(wacom->intf);
 }
 
 /*
- * Calculate the resolution of the X or Y axis, given appropriate HID data.
- * This function is little more than hidinput_calc_abs_res stripped down.
+ * Calculate the resolution of the X or Y axis using hidinput_calc_abs_res.
  */
 static int wacom_calc_hid_res(int logical_extents, int physical_extents,
-                              unsigned char unit, unsigned char exponent)
-{
-       int prev, unit_exponent;
-
-       /* Check if the extents are sane */
-       if (logical_extents <= 0 || physical_extents <= 0)
-               return 0;
-
-       /* Get signed value of nybble-sized twos-compliment exponent */
-       unit_exponent = exponent;
-       if (unit_exponent > 7)
-               unit_exponent -= 16;
-
-       /* Convert physical_extents to millimeters */
-       if (unit == 0x11) {             /* If centimeters */
-               unit_exponent += 1;
-       } else if (unit == 0x13) {      /* If inches */
-               prev = physical_extents;
-               physical_extents *= 254;
-               if (physical_extents < prev)
-                       return 0;
-               unit_exponent -= 1;
-       } else {
-               return 0;
-       }
-
-       /* Apply negative unit exponent */
-       for (; unit_exponent < 0; unit_exponent++) {
-               prev = logical_extents;
-               logical_extents *= 10;
-               if (logical_extents < prev)
-                       return 0;
-       }
-       /* Apply positive unit exponent */
-       for (; unit_exponent > 0; unit_exponent--) {
-               prev = physical_extents;
-               physical_extents *= 10;
-               if (physical_extents < prev)
-                       return 0;
-       }
-
-       /* Calculate resolution */
-       return logical_extents / physical_extents;
-}
-
-static int wacom_parse_logical_collection(unsigned char *report,
-                                         struct wacom_features *features)
+                              unsigned unit, int exponent)
 {
-       int length = 0;
-
-       if (features->type == BAMBOO_PT) {
-
-               /* Logical collection is only used by 3rd gen Bamboo Touch */
-               features->pktlen = WACOM_PKGLEN_BBTOUCH3;
-               features->device_type = BTN_TOOL_FINGER;
-
-               features->x_max = features->y_max =
-                       get_unaligned_le16(&report[10]);
-
-               length = 11;
-       }
-       return length;
+       struct hid_field field = {
+               .logical_maximum = logical_extents,
+               .physical_maximum = physical_extents,
+               .unit = unit,
+               .unit_exponent = exponent,
+       };
+
+       return hidinput_calc_abs_res(&field, ABS_X);
 }
 
-static void wacom_retrieve_report_data(struct usb_interface *intf,
-                                      struct wacom_features *features)
+static void wacom_feature_mapping(struct hid_device *hdev,
+               struct hid_field *field, struct hid_usage *usage)
 {
-       int result = 0;
-       unsigned char *rep_data;
-
-       rep_data = kmalloc(2, GFP_KERNEL);
-       if (rep_data) {
-
-               rep_data[0] = 12;
-               result = wacom_get_report(intf, WAC_HID_FEATURE_REPORT,
-                                         rep_data[0], rep_data, 2,
-                                         WAC_MSG_RETRIES);
-
-               if (result >= 0 && rep_data[1] > 2)
-                       features->touch_max = rep_data[1];
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       struct wacom_features *features = &wacom->wacom_wac.features;
 
-               kfree(rep_data);
+       switch (usage->hid) {
+       case HID_DG_CONTACTMAX:
+               /* leave touch_max as is if predefined */
+               if (!features->touch_max)
+                       features->touch_max = field->value[0];
+               break;
        }
 }
 
@@ -285,243 +145,100 @@ static void wacom_retrieve_report_data(struct usb_interface *intf,
  * interfaces haven't supported pressure or distance, this is enough
  * information to override invalid values in the wacom_features table.
  *
- * 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical
- * Collection. Instead they define a Logical Collection with a single
- * Logical Maximum for both X and Y.
- *
- * Intuos5 touch interface does not contain useful data. We deal with
- * this after returning from this function.
+ * Intuos5 touch interface and 3rd gen Bamboo Touch do not contain useful
+ * data. We deal with them after returning from this function.
  */
-static int wacom_parse_hid(struct usb_interface *intf,
-                          struct hid_descriptor *hid_desc,
-                          struct wacom_features *features)
+static void wacom_usage_mapping(struct hid_device *hdev,
+               struct hid_field *field, struct hid_usage *usage)
 {
-       struct usb_device *dev = interface_to_usbdev(intf);
-       char limit = 0;
-       /* result has to be defined as int for some devices */
-       int result = 0, touch_max = 0;
-       int i = 0, page = 0, finger = 0, pen = 0;
-       unsigned char *report;
-
-       report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL);
-       if (!report)
-               return -ENOMEM;
-
-       /* retrive report descriptors */
-       do {
-               result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-                       USB_REQ_GET_DESCRIPTOR,
-                       USB_RECIP_INTERFACE | USB_DIR_IN,
-                       HID_DEVICET_REPORT << 8,
-                       intf->altsetting[0].desc.bInterfaceNumber, /* interface */
-                       report,
-                       hid_desc->wDescriptorLength,
-                       5000); /* 5 secs */
-       } while (result < 0 && limit++ < WAC_MSG_RETRIES);
-
-       /* No need to parse the Descriptor. It isn't an error though */
-       if (result < 0)
-               goto out;
-
-       for (i = 0; i < hid_desc->wDescriptorLength; i++) {
-
-               switch (report[i]) {
-               case HID_USAGE_PAGE:
-                       page = report[i + 1];
-                       i++;
-                       break;
-
-               case HID_USAGE:
-                       switch (page << 16 | report[i + 1]) {
-                       case HID_USAGE_X:
-                               if (finger) {
-                                       features->device_type = BTN_TOOL_FINGER;
-                                       /* touch device at least supports one touch point */
-                                       touch_max = 1;
-                                       switch (features->type) {
-                                       case TABLETPC2FG:
-                                               features->pktlen = WACOM_PKGLEN_TPC2FG;
-                                               break;
-
-                                       case MTSCREEN:
-                                       case WACOM_24HDT:
-                                               features->pktlen = WACOM_PKGLEN_MTOUCH;
-                                               break;
-
-                                       case MTTPC:
-                                       case MTTPC_B:
-                                               features->pktlen = WACOM_PKGLEN_MTTPC;
-                                               break;
-
-                                       case BAMBOO_PT:
-                                               features->pktlen = WACOM_PKGLEN_BBTOUCH;
-                                               break;
-
-                                       default:
-                                               features->pktlen = WACOM_PKGLEN_GRAPHIRE;
-                                               break;
-                                       }
-
-                                       switch (features->type) {
-                                       case BAMBOO_PT:
-                                               features->x_phy =
-                                                       get_unaligned_le16(&report[i + 5]);
-                                               features->x_max =
-                                                       get_unaligned_le16(&report[i + 8]);
-                                               i += 15;
-                                               break;
-
-                                       case WACOM_24HDT:
-                                               features->x_max =
-                                                       get_unaligned_le16(&report[i + 3]);
-                                               features->x_phy =
-                                                       get_unaligned_le16(&report[i + 8]);
-                                               features->unit = report[i - 1];
-                                               features->unitExpo = report[i - 3];
-                                               i += 12;
-                                               break;
-
-                                       case MTTPC_B:
-                                               features->x_max =
-                                                       get_unaligned_le16(&report[i + 3]);
-                                               features->x_phy =
-                                                       get_unaligned_le16(&report[i + 6]);
-                                               features->unit = report[i - 5];
-                                               features->unitExpo = report[i - 3];
-                                               i += 9;
-                                               break;
-
-                                       default:
-                                               features->x_max =
-                                                       get_unaligned_le16(&report[i + 3]);
-                                               features->x_phy =
-                                                       get_unaligned_le16(&report[i + 6]);
-                                               features->unit = report[i + 9];
-                                               features->unitExpo = report[i + 11];
-                                               i += 12;
-                                               break;
-                                       }
-                               } else if (pen) {
-                                       /* penabled only accepts exact bytes of data */
-                                       if (features->type >= TABLETPC)
-                                               features->pktlen = WACOM_PKGLEN_GRAPHIRE;
-                                       features->device_type = BTN_TOOL_PEN;
-                                       features->x_max =
-                                               get_unaligned_le16(&report[i + 3]);
-                                       i += 4;
-                               }
-                               break;
-
-                       case HID_USAGE_Y:
-                               if (finger) {
-                                       switch (features->type) {
-                                       case TABLETPC2FG:
-                                       case MTSCREEN:
-                                       case MTTPC:
-                                               features->y_max =
-                                                       get_unaligned_le16(&report[i + 3]);
-                                               features->y_phy =
-                                                       get_unaligned_le16(&report[i + 6]);
-                                               i += 7;
-                                               break;
-
-                                       case WACOM_24HDT:
-                                               features->y_max =
-                                                       get_unaligned_le16(&report[i + 3]);
-                                               features->y_phy =
-                                                       get_unaligned_le16(&report[i - 2]);
-                                               i += 7;
-                                               break;
-
-                                       case BAMBOO_PT:
-                                               features->y_phy =
-                                                       get_unaligned_le16(&report[i + 3]);
-                                               features->y_max =
-                                                       get_unaligned_le16(&report[i + 6]);
-                                               i += 12;
-                                               break;
-
-                                       case MTTPC_B:
-                                               features->y_max =
-                                                       get_unaligned_le16(&report[i + 3]);
-                                               features->y_phy =
-                                                       get_unaligned_le16(&report[i + 6]);
-                                               i += 9;
-                                               break;
-
-                                       default:
-                                               features->y_max =
-                                                       features->x_max;
-                                               features->y_phy =
-                                                       get_unaligned_le16(&report[i + 3]);
-                                               i += 4;
-                                               break;
-                                       }
-                               } else if (pen) {
-                                       features->y_max =
-                                               get_unaligned_le16(&report[i + 3]);
-                                       i += 4;
-                               }
-                               break;
-
-                       case HID_USAGE_FINGER:
-                               finger = 1;
-                               i++;
-                               break;
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       struct wacom_features *features = &wacom->wacom_wac.features;
+       bool finger = (field->logical == HID_DG_FINGER) ||
+                     (field->physical == HID_DG_FINGER);
+       bool pen = (field->logical == HID_DG_STYLUS) ||
+                  (field->physical == HID_DG_STYLUS);
 
-                       /*
-                        * Requiring Stylus Usage will ignore boot mouse
-                        * X/Y values and some cases of invalid Digitizer X/Y
-                        * values commonly reported.
-                        */
-                       case HID_USAGE_STYLUS:
-                               pen = 1;
-                               i++;
-                               break;
+       /*
+       * Requiring Stylus Usage will ignore boot mouse
+       * X/Y values and some cases of invalid Digitizer X/Y
+       * values commonly reported.
+       */
+       if (!pen && !finger)
+               return;
 
-                       case HID_USAGE_CONTACTMAX:
-                               /* leave touch_max as is if predefined */
-                               if (!features->touch_max)
-                                       wacom_retrieve_report_data(intf, features);
-                               i++;
-                               break;
+       if (finger && !features->touch_max)
+               /* touch device at least supports one touch point */
+               features->touch_max = 1;
 
-                       case HID_USAGE_PRESSURE:
-                               if (pen) {
-                                       features->pressure_max =
-                                               get_unaligned_le16(&report[i + 3]);
-                                       i += 4;
-                               }
-                               break;
+       switch (usage->hid) {
+       case HID_GD_X:
+               features->x_max = field->logical_maximum;
+               if (finger) {
+                       features->device_type = BTN_TOOL_FINGER;
+                       features->x_phy = field->physical_maximum;
+                       if (features->type != BAMBOO_PT) {
+                               features->unit = field->unit;
+                               features->unitExpo = field->unit_exponent;
                        }
-                       break;
-
-               case HID_COLLECTION_END:
-                       /* reset UsagePage and Finger */
-                       finger = page = 0;
-                       break;
+               } else {
+                       features->device_type = BTN_TOOL_PEN;
+               }
+               break;
+       case HID_GD_Y:
+               features->y_max = field->logical_maximum;
+               if (finger) {
+                       features->y_phy = field->physical_maximum;
+                       if (features->type != BAMBOO_PT) {
+                               features->unit = field->unit;
+                               features->unitExpo = field->unit_exponent;
+                       }
+               }
+               break;
+       case HID_DG_TIPPRESSURE:
+               if (pen)
+                       features->pressure_max = field->logical_maximum;
+               break;
+       }
+}
 
-               case HID_COLLECTION:
-                       i++;
-                       switch (report[i]) {
-                       case HID_COLLECTION_LOGICAL:
-                               i += wacom_parse_logical_collection(&report[i],
-                                                                   features);
-                               break;
+static void wacom_parse_hid(struct hid_device *hdev,
+                          struct wacom_features *features)
+{
+       struct hid_report_enum *rep_enum;
+       struct hid_report *hreport;
+       int i, j;
+
+       /* check features first */
+       rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
+       list_for_each_entry(hreport, &rep_enum->report_list, list) {
+               for (i = 0; i < hreport->maxfield; i++) {
+                       /* Ignore if report count is out of bounds. */
+                       if (hreport->field[i]->report_count < 1)
+                               continue;
+
+                       for (j = 0; j < hreport->field[i]->maxusage; j++) {
+                               wacom_feature_mapping(hdev, hreport->field[i],
+                                               hreport->field[i]->usage + j);
                        }
-                       break;
                }
        }
 
- out:
-       if (!features->touch_max && touch_max)
-               features->touch_max = touch_max;
-       result = 0;
-       kfree(report);
-       return result;
+       /* now check the input usages */
+       rep_enum = &hdev->report_enum[HID_INPUT_REPORT];
+       list_for_each_entry(hreport, &rep_enum->report_list, list) {
+
+               if (!hreport->maxfield)
+                       continue;
+
+               for (i = 0; i < hreport->maxfield; i++)
+                       for (j = 0; j < hreport->field[i]->maxusage; j++)
+                               wacom_usage_mapping(hdev, hreport->field[i],
+                                               hreport->field[i]->usage + j);
+       }
 }
 
-static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int length, int mode)
+static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
+               int length, int mode)
 {
        unsigned char *rep_data;
        int error = -ENOMEM, limit = 0;
@@ -534,8 +251,11 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int
                rep_data[0] = report_id;
                rep_data[1] = mode;
 
-               error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
-                                        report_id, rep_data, length, 1);
+               error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data,
+                                        length, 1);
+               if (error >= 0)
+                       error = wacom_get_report(hdev, HID_FEATURE_REPORT,
+                                                report_id, rep_data, length, 1);
        } while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES);
 
        kfree(rep_data);
@@ -543,6 +263,59 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int
        return error < 0 ? error : 0;
 }
 
+static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed,
+               struct wacom_features *features)
+{
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       int ret;
+       u8 rep_data[2];
+
+       switch (features->type) {
+       case GRAPHIRE_BT:
+               rep_data[0] = 0x03;
+               rep_data[1] = 0x00;
+               ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2,
+                                       3);
+
+               if (ret >= 0) {
+                       rep_data[0] = speed == 0 ? 0x05 : 0x06;
+                       rep_data[1] = 0x00;
+
+                       ret = wacom_set_report(hdev, HID_FEATURE_REPORT,
+                                               rep_data, 2, 3);
+
+                       if (ret >= 0) {
+                               wacom->wacom_wac.bt_high_speed = speed;
+                               return 0;
+                       }
+               }
+
+               /*
+                * Note that if the raw queries fail, it's not a hard failure
+                * and it is safe to continue
+                */
+               hid_warn(hdev, "failed to poke device, command %d, err %d\n",
+                        rep_data[0], ret);
+               break;
+       case INTUOS4WL:
+               if (speed == 1)
+                       wacom->wacom_wac.bt_features &= ~0x20;
+               else
+                       wacom->wacom_wac.bt_features |= 0x20;
+
+               rep_data[0] = 0x03;
+               rep_data[1] = wacom->wacom_wac.bt_features;
+
+               ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2,
+                                       1);
+               if (ret >= 0)
+                       wacom->wacom_wac.bt_high_speed = speed;
+               break;
+       }
+
+       return 0;
+}
+
 /*
  * Switch the tablet into its most-capable mode. Wacom tablets are
  * typically configured to power-up in a mode which sends mouse-like
@@ -550,31 +323,34 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int
  * 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 usb_interface *intf, struct wacom_features *features)
+static int wacom_query_tablet_data(struct hid_device *hdev,
+               struct wacom_features *features)
 {
+       if (hdev->bus == BUS_BLUETOOTH)
+               return wacom_bt_query_tablet_data(hdev, 1, features);
+
        if (features->device_type == BTN_TOOL_FINGER) {
                if (features->type > TABLETPC) {
                        /* MT Tablet PC touch */
-                       return wacom_set_device_mode(intf, 3, 4, 4);
+                       return wacom_set_device_mode(hdev, 3, 4, 4);
                }
                else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) {
-                       return wacom_set_device_mode(intf, 18, 3, 2);
+                       return wacom_set_device_mode(hdev, 18, 3, 2);
                }
        } else if (features->device_type == BTN_TOOL_PEN) {
                if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
-                       return wacom_set_device_mode(intf, 2, 2, 2);
+                       return wacom_set_device_mode(hdev, 2, 2, 2);
                }
        }
 
        return 0;
 }
 
-static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
+static void wacom_retrieve_hid_descriptor(struct hid_device *hdev,
                                         struct wacom_features *features)
 {
-       int error = 0;
-       struct usb_host_interface *interface = intf->cur_altsetting;
-       struct hid_descriptor *hid_desc;
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       struct usb_interface *intf = wacom->intf;
 
        /* default features */
        features->device_type = BTN_TOOL_PEN;
@@ -599,66 +375,54 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
        }
 
        /* only devices that support touch need to retrieve the info */
-       if (features->type < BAMBOO_PT) {
-               goto out;
-       }
-
-       error = usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc);
-       if (error) {
-               error = usb_get_extra_descriptor(&interface->endpoint[0],
-                                                HID_DEVICET_REPORT, &hid_desc);
-               if (error) {
-                       dev_err(&intf->dev,
-                               "can not retrieve extra class descriptor\n");
-                       goto out;
-               }
-       }
-       error = wacom_parse_hid(intf, hid_desc, features);
+       if (features->type < BAMBOO_PT)
+               return;
 
- out:
-       return error;
+       wacom_parse_hid(hdev, features);
 }
 
-struct wacom_usbdev_data {
+struct wacom_hdev_data {
        struct list_head list;
        struct kref kref;
-       struct usb_device *dev;
+       struct hid_device *dev;
        struct wacom_shared shared;
 };
 
 static LIST_HEAD(wacom_udev_list);
 static DEFINE_MUTEX(wacom_udev_list_lock);
 
-static struct usb_device *wacom_get_sibling(struct usb_device *dev, int vendor, int product)
+static bool wacom_are_sibling(struct hid_device *hdev,
+               struct hid_device *sibling)
 {
-       int port1;
-       struct usb_device *sibling;
-
-       if (vendor == 0 && product == 0)
-               return dev;
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       struct wacom_features *features = &wacom->wacom_wac.features;
+       int vid = features->oVid;
+       int pid = features->oPid;
+       int n1,n2;
 
-       if (dev->parent == NULL)
-               return NULL;
+       if (vid == 0 && pid == 0) {
+               vid = hdev->vendor;
+               pid = hdev->product;
+       }
 
-       usb_hub_for_each_child(dev->parent, port1, sibling) {
-               struct usb_device_descriptor *d;
-               if (sibling == NULL)
-                       continue;
+       if (vid != sibling->vendor || pid != sibling->product)
+               return false;
 
-               d = &sibling->descriptor;
-               if (d->idVendor == vendor && d->idProduct == product)
-                       return sibling;
-       }
+       /* Compare the physical path. */
+       n1 = strrchr(hdev->phys, '.') - hdev->phys;
+       n2 = strrchr(sibling->phys, '.') - sibling->phys;
+       if (n1 != n2 || n1 <= 0 || n2 <= 0)
+               return false;
 
-       return NULL;
+       return !strncmp(hdev->phys, sibling->phys, n1);
 }
 
-static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev)
+static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
 {
-       struct wacom_usbdev_data *data;
+       struct wacom_hdev_data *data;
 
        list_for_each_entry(data, &wacom_udev_list, list) {
-               if (data->dev == dev) {
+               if (wacom_are_sibling(hdev, data->dev)) {
                        kref_get(&data->kref);
                        return data;
                }
@@ -667,28 +431,29 @@ static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev)
        return NULL;
 }
 
-static int wacom_add_shared_data(struct wacom_wac *wacom,
-                                struct usb_device *dev)
+static int wacom_add_shared_data(struct hid_device *hdev)
 {
-       struct wacom_usbdev_data *data;
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+       struct wacom_hdev_data *data;
        int retval = 0;
 
        mutex_lock(&wacom_udev_list_lock);
 
-       data = wacom_get_usbdev_data(dev);
+       data = wacom_get_hdev_data(hdev);
        if (!data) {
-               data = kzalloc(sizeof(struct wacom_usbdev_data), GFP_KERNEL);
+               data = kzalloc(sizeof(struct wacom_hdev_data), GFP_KERNEL);
                if (!data) {
                        retval = -ENOMEM;
                        goto out;
                }
 
                kref_init(&data->kref);
-               data->dev = dev;
+               data->dev = hdev;
                list_add_tail(&data->list, &wacom_udev_list);
        }
 
-       wacom->shared = &data->shared;
+       wacom_wac->shared = &data->shared;
 
 out:
        mutex_unlock(&wacom_udev_list_lock);
@@ -697,8 +462,8 @@ out:
 
 static void wacom_release_shared_data(struct kref *kref)
 {
-       struct wacom_usbdev_data *data =
-               container_of(kref, struct wacom_usbdev_data, kref);
+       struct wacom_hdev_data *data =
+               container_of(kref, struct wacom_hdev_data, kref);
 
        mutex_lock(&wacom_udev_list_lock);
        list_del(&data->list);
@@ -709,10 +474,10 @@ static void wacom_release_shared_data(struct kref *kref)
 
 static void wacom_remove_shared_data(struct wacom_wac *wacom)
 {
-       struct wacom_usbdev_data *data;
+       struct wacom_hdev_data *data;
 
        if (wacom->shared) {
-               data = container_of(wacom->shared, struct wacom_usbdev_data, shared);
+               data = container_of(wacom->shared, struct wacom_hdev_data, shared);
                kref_put(&data->kref, wacom_release_shared_data);
                wacom->shared = NULL;
        }
@@ -755,38 +520,40 @@ static int wacom_led_control(struct wacom *wacom)
                buf[4] = wacom->led.img_lum;
        }
 
-       retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL,
-                                 buf, 9, WAC_CMD_RETRIES);
+       retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 9,
+                                 WAC_CMD_RETRIES);
        kfree(buf);
 
        return retval;
 }
 
-static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img)
+static int wacom_led_putimage(struct wacom *wacom, int button_id, u8 xfer_id,
+               const unsigned len, const void *img)
 {
        unsigned char *buf;
        int i, retval;
+       const unsigned chunk_len = len / 4; /* 4 chunks are needed to be sent */
 
-       buf = kzalloc(259, GFP_KERNEL);
+       buf = kzalloc(chunk_len + 3 , GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
        /* Send 'start' command */
        buf[0] = WAC_CMD_ICON_START;
        buf[1] = 1;
-       retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START,
-                                 buf, 2, WAC_CMD_RETRIES);
+       retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2,
+                                 WAC_CMD_RETRIES);
        if (retval < 0)
                goto out;
 
-       buf[0] = WAC_CMD_ICON_XFER;
+       buf[0] = xfer_id;
        buf[1] = button_id & 0x07;
        for (i = 0; i < 4; i++) {
                buf[2] = i;
-               memcpy(buf + 3, img + i * 256, 256);
+               memcpy(buf + 3, img + i * chunk_len, chunk_len);
 
-               retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_XFER,
-                                         buf, 259, WAC_CMD_RETRIES);
+               retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
+                                         buf, chunk_len + 3, WAC_CMD_RETRIES);
                if (retval < 0)
                        break;
        }
@@ -794,8 +561,8 @@ static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *im
        /* Send 'stop' */
        buf[0] = WAC_CMD_ICON_START;
        buf[1] = 0;
-       wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START,
-                        buf, 2, WAC_CMD_RETRIES);
+       wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2,
+                        WAC_CMD_RETRIES);
 
 out:
        kfree(buf);
@@ -805,7 +572,8 @@ out:
 static ssize_t wacom_led_select_store(struct device *dev, int set_id,
                                      const char *buf, size_t count)
 {
-       struct wacom *wacom = dev_get_drvdata(dev);
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct wacom *wacom = hid_get_drvdata(hdev);
        unsigned int id;
        int err;
 
@@ -832,7 +600,8 @@ static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \
 static ssize_t wacom_led##SET_ID##_select_show(struct device *dev,     \
        struct device_attribute *attr, char *buf)                       \
 {                                                                      \
-       struct wacom *wacom = dev_get_drvdata(dev);                     \
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
+       struct wacom *wacom = hid_get_drvdata(hdev);                    \
        return snprintf(buf, 2, "%d\n", wacom->led.select[SET_ID]);     \
 }                                                                      \
 static DEVICE_ATTR(status_led##SET_ID##_select, S_IWUSR | S_IRUSR,     \
@@ -866,7 +635,8 @@ static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
 static ssize_t wacom_##name##_luminance_store(struct device *dev,      \
        struct device_attribute *attr, const char *buf, size_t count)   \
 {                                                                      \
-       struct wacom *wacom = dev_get_drvdata(dev);                     \
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
+       struct wacom *wacom = hid_get_drvdata(hdev);                    \
                                                                        \
        return wacom_luminance_store(wacom, &wacom->led.field,          \
                                     buf, count);                       \
@@ -881,15 +651,26 @@ DEVICE_LUMINANCE_ATTR(buttons, img_lum);
 static ssize_t wacom_button_image_store(struct device *dev, int button_id,
                                        const char *buf, size_t count)
 {
-       struct wacom *wacom = dev_get_drvdata(dev);
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct wacom *wacom = hid_get_drvdata(hdev);
        int err;
+       unsigned len;
+       u8 xfer_id;
+
+       if (hdev->bus == BUS_BLUETOOTH) {
+               len = 256;
+               xfer_id = WAC_CMD_ICON_BT_XFER;
+       } else {
+               len = 1024;
+               xfer_id = WAC_CMD_ICON_XFER;
+       }
 
-       if (count != 1024)
+       if (count != len)
                return -EINVAL;
 
        mutex_lock(&wacom->lock);
 
-       err = wacom_led_putimage(wacom, button_id, buf);
+       err = wacom_led_putimage(wacom, button_id, xfer_id, len, buf);
 
        mutex_unlock(&wacom->lock);
 
@@ -965,13 +746,14 @@ static int wacom_initialize_leds(struct wacom *wacom)
        switch (wacom->wacom_wac.features.type) {
        case INTUOS4S:
        case INTUOS4:
+       case INTUOS4WL:
        case INTUOS4L:
                wacom->led.select[0] = 0;
                wacom->led.select[1] = 0;
                wacom->led.llv = 10;
                wacom->led.hlv = 20;
                wacom->led.img_lum = 10;
-               error = sysfs_create_group(&wacom->intf->dev.kobj,
+               error = sysfs_create_group(&wacom->hdev->dev.kobj,
                                           &intuos4_led_attr_group);
                break;
 
@@ -983,7 +765,7 @@ static int wacom_initialize_leds(struct wacom *wacom)
                wacom->led.hlv = 0;
                wacom->led.img_lum = 0;
 
-               error = sysfs_create_group(&wacom->intf->dev.kobj,
+               error = sysfs_create_group(&wacom->hdev->dev.kobj,
                                           &cintiq_led_attr_group);
                break;
 
@@ -1000,7 +782,7 @@ static int wacom_initialize_leds(struct wacom *wacom)
                        wacom->led.hlv = 0;
                        wacom->led.img_lum = 0;
 
-                       error = sysfs_create_group(&wacom->intf->dev.kobj,
+                       error = sysfs_create_group(&wacom->hdev->dev.kobj,
                                                  &intuos5_led_attr_group);
                } else
                        return 0;
@@ -1011,28 +793,35 @@ static int wacom_initialize_leds(struct wacom *wacom)
        }
 
        if (error) {
-               dev_err(&wacom->intf->dev,
+               hid_err(wacom->hdev,
                        "cannot create sysfs group err: %d\n", error);
                return error;
        }
        wacom_led_control(wacom);
+       wacom->led_initialized = true;
 
        return 0;
 }
 
 static void wacom_destroy_leds(struct wacom *wacom)
 {
+       if (!wacom->led_initialized)
+               return;
+
+       wacom->led_initialized = false;
+
        switch (wacom->wacom_wac.features.type) {
        case INTUOS4S:
        case INTUOS4:
+       case INTUOS4WL:
        case INTUOS4L:
-               sysfs_remove_group(&wacom->intf->dev.kobj,
+               sysfs_remove_group(&wacom->hdev->dev.kobj,
                                   &intuos4_led_attr_group);
                break;
 
        case WACOM_24HD:
        case WACOM_21UX2:
-               sysfs_remove_group(&wacom->intf->dev.kobj,
+               sysfs_remove_group(&wacom->hdev->dev.kobj,
                                   &cintiq_led_attr_group);
                break;
 
@@ -1043,17 +832,24 @@ static void wacom_destroy_leds(struct wacom *wacom)
        case INTUOSPM:
        case INTUOSPL:
                if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN)
-                       sysfs_remove_group(&wacom->intf->dev.kobj,
+                       sysfs_remove_group(&wacom->hdev->dev.kobj,
                                           &intuos5_led_attr_group);
                break;
        }
 }
 
 static enum power_supply_property wacom_battery_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_SCOPE,
        POWER_SUPPLY_PROP_CAPACITY
 };
 
+static enum power_supply_property wacom_ac_props[] = {
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_SCOPE,
+};
+
 static int wacom_battery_get_property(struct power_supply *psy,
                                      enum power_supply_property psp,
                                      union power_supply_propval *val)
@@ -1067,7 +863,16 @@ static int wacom_battery_get_property(struct power_supply *psy,
                        break;
                case POWER_SUPPLY_PROP_CAPACITY:
                        val->intval =
-                               wacom->wacom_wac.battery_capacity * 100 / 31;
+                               wacom->wacom_wac.battery_capacity;
+                       break;
+               case POWER_SUPPLY_PROP_STATUS:
+                       if (wacom->wacom_wac.bat_charging)
+                               val->intval = POWER_SUPPLY_STATUS_CHARGING;
+                       else if (wacom->wacom_wac.battery_capacity == 100 &&
+                                   wacom->wacom_wac.ps_connected)
+                               val->intval = POWER_SUPPLY_STATUS_FULL;
+                       else
+                               val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
                        break;
                default:
                        ret = -EINVAL;
@@ -1077,74 +882,201 @@ static int wacom_battery_get_property(struct power_supply *psy,
        return ret;
 }
 
+static int wacom_ac_get_property(struct power_supply *psy,
+                               enum power_supply_property psp,
+                               union power_supply_propval *val)
+{
+       struct wacom *wacom = container_of(psy, struct wacom, ac);
+       int ret = 0;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_PRESENT:
+               /* fall through */
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = wacom->wacom_wac.ps_connected;
+               break;
+       case POWER_SUPPLY_PROP_SCOPE:
+               val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
 static int wacom_initialize_battery(struct wacom *wacom)
 {
-       int error = 0;
+       static atomic_t battery_no = ATOMIC_INIT(0);
+       int error;
+       unsigned long n;
+
+       if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) {
+               n = atomic_inc_return(&battery_no) - 1;
 
-       if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR) {
                wacom->battery.properties = wacom_battery_props;
                wacom->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
                wacom->battery.get_property = wacom_battery_get_property;
-               wacom->battery.name = "wacom_battery";
+               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;
 
-               error = power_supply_register(&wacom->usbdev->dev,
+               wacom->ac.properties = wacom_ac_props;
+               wacom->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
+               wacom->ac.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);
 
-               if (!error)
-                       power_supply_powers(&wacom->battery,
-                                           &wacom->usbdev->dev);
+               error = power_supply_register(&wacom->hdev->dev, &wacom->ac);
+               if (error) {
+                       power_supply_unregister(&wacom->battery);
+                       return error;
+               }
+
+               power_supply_powers(&wacom->ac, &wacom->hdev->dev);
        }
 
-       return error;
+       return 0;
 }
 
 static void wacom_destroy_battery(struct wacom *wacom)
 {
-       if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR &&
-           wacom->battery.dev) {
+       if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
+            wacom->battery.dev) {
                power_supply_unregister(&wacom->battery);
                wacom->battery.dev = NULL;
+               power_supply_unregister(&wacom->ac);
+               wacom->ac.dev = NULL;
        }
 }
 
-static int wacom_register_input(struct wacom *wacom)
+static ssize_t wacom_show_speed(struct device *dev,
+                               struct device_attribute
+                               *attr, char *buf)
+{
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct wacom *wacom = hid_get_drvdata(hdev);
+
+       return snprintf(buf, PAGE_SIZE, "%i\n", wacom->wacom_wac.bt_high_speed);
+}
+
+static ssize_t wacom_store_speed(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       u8 new_speed;
+
+       if (kstrtou8(buf, 0, &new_speed))
+               return -EINVAL;
+
+       if (new_speed != 0 && new_speed != 1)
+               return -EINVAL;
+
+       wacom_bt_query_tablet_data(hdev, new_speed, &wacom->wacom_wac.features);
+
+       return count;
+}
+
+static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
+               wacom_show_speed, wacom_store_speed);
+
+static struct input_dev *wacom_allocate_input(struct wacom *wacom)
 {
        struct input_dev *input_dev;
-       struct usb_interface *intf = wacom->intf;
-       struct usb_device *dev = interface_to_usbdev(intf);
+       struct hid_device *hdev = wacom->hdev;
        struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
-       int error;
 
        input_dev = input_allocate_device();
-       if (!input_dev) {
-               error = -ENOMEM;
-               goto fail1;
-       }
+       if (!input_dev)
+               return NULL;
 
        input_dev->name = wacom_wac->name;
-       input_dev->dev.parent = &intf->dev;
+       input_dev->phys = hdev->phys;
+       input_dev->dev.parent = &hdev->dev;
        input_dev->open = wacom_open;
        input_dev->close = wacom_close;
-       usb_to_input_id(dev, &input_dev->id);
+       input_dev->uniq = hdev->uniq;
+       input_dev->id.bustype = hdev->bus;
+       input_dev->id.vendor  = hdev->vendor;
+       input_dev->id.product = hdev->product;
+       input_dev->id.version = hdev->version;
        input_set_drvdata(input_dev, wacom);
 
+       return input_dev;
+}
+
+static void wacom_unregister_inputs(struct wacom *wacom)
+{
+       if (wacom->wacom_wac.input)
+               input_unregister_device(wacom->wacom_wac.input);
+       if (wacom->wacom_wac.pad_input)
+               input_unregister_device(wacom->wacom_wac.pad_input);
+       wacom->wacom_wac.input = NULL;
+       wacom->wacom_wac.pad_input = NULL;
+}
+
+static int wacom_register_inputs(struct wacom *wacom)
+{
+       struct input_dev *input_dev, *pad_input_dev;
+       struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+       int error;
+
+       input_dev = wacom_allocate_input(wacom);
+       pad_input_dev = wacom_allocate_input(wacom);
+       if (!input_dev || !pad_input_dev) {
+               error = -ENOMEM;
+               goto fail1;
+       }
+
        wacom_wac->input = input_dev;
+       wacom_wac->pad_input = pad_input_dev;
+       wacom_wac->pad_input->name = wacom_wac->pad_name;
+
        error = wacom_setup_input_capabilities(input_dev, wacom_wac);
        if (error)
-               goto fail1;
+               goto fail2;
 
        error = input_register_device(input_dev);
        if (error)
                goto fail2;
 
+       error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
+       if (error) {
+               /* no pad in use on this interface */
+               input_free_device(pad_input_dev);
+               wacom_wac->pad_input = NULL;
+               pad_input_dev = NULL;
+       } else {
+               error = input_register_device(pad_input_dev);
+               if (error)
+                       goto fail3;
+       }
+
        return 0;
 
+fail3:
+       input_unregister_device(input_dev);
+       input_dev = NULL;
 fail2:
-       input_free_device(input_dev);
        wacom_wac->input = NULL;
+       wacom_wac->pad_input = NULL;
 fail1:
+       if (input_dev)
+               input_free_device(input_dev);
+       if (pad_input_dev)
+               input_free_device(pad_input_dev);
        return error;
 }
 
@@ -1153,6 +1085,7 @@ static void wacom_wireless_work(struct work_struct *work)
        struct wacom *wacom = container_of(work, struct wacom, work);
        struct usb_device *usbdev = wacom->usbdev;
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+       struct hid_device *hdev1, *hdev2;
        struct wacom *wacom1, *wacom2;
        struct wacom_wac *wacom_wac1, *wacom_wac2;
        int error;
@@ -1165,50 +1098,49 @@ static void wacom_wireless_work(struct work_struct *work)
        wacom_destroy_battery(wacom);
 
        /* Stylus interface */
-       wacom1 = usb_get_intfdata(usbdev->config->interface[1]);
+       hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
+       wacom1 = hid_get_drvdata(hdev1);
        wacom_wac1 = &(wacom1->wacom_wac);
-       if (wacom_wac1->input)
-               input_unregister_device(wacom_wac1->input);
-       wacom_wac1->input = NULL;
+       wacom_unregister_inputs(wacom1);
 
        /* Touch interface */
-       wacom2 = usb_get_intfdata(usbdev->config->interface[2]);
+       hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
+       wacom2 = hid_get_drvdata(hdev2);
        wacom_wac2 = &(wacom2->wacom_wac);
-       if (wacom_wac2->input)
-               input_unregister_device(wacom_wac2->input);
-       wacom_wac2->input = NULL;
+       wacom_unregister_inputs(wacom2);
 
        if (wacom_wac->pid == 0) {
-               dev_info(&wacom->intf->dev, "wireless tablet disconnected\n");
+               hid_info(wacom->hdev, "wireless tablet disconnected\n");
+               wacom_wac1->shared->type = 0;
        } else {
-               const struct usb_device_id *id = wacom_ids;
+               const struct hid_device_id *id = wacom_ids;
 
-               dev_info(&wacom->intf->dev,
-                        "wireless tablet connected with PID %x\n",
+               hid_info(wacom->hdev, "wireless tablet connected with PID %x\n",
                         wacom_wac->pid);
 
-               while (id->match_flags) {
-                       if (id->idVendor == USB_VENDOR_ID_WACOM &&
-                           id->idProduct == wacom_wac->pid)
+               while (id->bus) {
+                       if (id->vendor == USB_VENDOR_ID_WACOM &&
+                           id->product == wacom_wac->pid)
                                break;
                        id++;
                }
 
-               if (!id->match_flags) {
-                       dev_info(&wacom->intf->dev,
-                                "ignoring unknown PID.\n");
+               if (!id->bus) {
+                       hid_info(wacom->hdev, "ignoring unknown PID.\n");
                        return;
                }
 
                /* Stylus interface */
                wacom_wac1->features =
-                       *((struct wacom_features *)id->driver_info);
+                       *((struct wacom_features *)id->driver_data);
                wacom_wac1->features.device_type = BTN_TOOL_PEN;
                snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen",
                         wacom_wac1->features.name);
+               snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",
+                        wacom_wac1->features.name);
                wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max;
                wacom_wac1->shared->type = wacom_wac1->features.type;
-               error = wacom_register_input(wacom1);
+               error = wacom_register_inputs(wacom1);
                if (error)
                        goto fail;
 
@@ -1216,7 +1148,7 @@ static void wacom_wireless_work(struct work_struct *work)
                if (wacom_wac1->features.touch_max ||
                    wacom_wac1->features.type == INTUOSHT) {
                        wacom_wac2->features =
-                               *((struct wacom_features *)id->driver_info);
+                               *((struct wacom_features *)id->driver_data);
                        wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
                        wacom_wac2->features.device_type = BTN_TOOL_FINGER;
                        wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
@@ -1226,7 +1158,9 @@ static void wacom_wireless_work(struct work_struct *work)
                        else
                                snprintf(wacom_wac2->name, WACOM_NAME_MAX,
                                         "%s (WL) Pad",wacom_wac2->features.name);
-                       error = wacom_register_input(wacom2);
+                       snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
+                                "%s (WL) Pad", wacom_wac2->features.name);
+                       error = wacom_register_inputs(wacom2);
                        if (error)
                                goto fail;
 
@@ -1243,15 +1177,8 @@ static void wacom_wireless_work(struct work_struct *work)
        return;
 
 fail:
-       if (wacom_wac2->input) {
-               input_unregister_device(wacom_wac2->input);
-               wacom_wac2->input = NULL;
-       }
-
-       if (wacom_wac1->input) {
-               input_unregister_device(wacom_wac1->input);
-               wacom_wac1->input = NULL;
-       }
+       wacom_unregister_inputs(wacom1);
+       wacom_unregister_inputs(wacom2);
        return;
 }
 
@@ -1282,69 +1209,89 @@ static void wacom_calculate_res(struct wacom_features *features)
                                                    features->unitExpo);
 }
 
-static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int wacom_hid_report_len(struct hid_report *report)
+{
+       /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
+       return ((report->size - 1) >> 3) + 1 + (report->id > 0);
+}
+
+static size_t wacom_compute_pktlen(struct hid_device *hdev)
+{
+       struct hid_report_enum *report_enum;
+       struct hid_report *report;
+       size_t size = 0;
+
+       report_enum = hdev->report_enum + HID_INPUT_REPORT;
+
+       list_for_each_entry(report, &report_enum->report_list, list) {
+               size_t report_size = wacom_hid_report_len(report);
+               if (report_size > size)
+                       size = report_size;
+       }
+
+       return size;
+}
+
+static int wacom_probe(struct hid_device *hdev,
+               const struct hid_device_id *id)
 {
+       struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
        struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_endpoint_descriptor *endpoint;
        struct wacom *wacom;
        struct wacom_wac *wacom_wac;
        struct wacom_features *features;
        int error;
 
-       if (!id->driver_info)
+       if (!id->driver_data)
                return -EINVAL;
 
        wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
        if (!wacom)
                return -ENOMEM;
 
+       hid_set_drvdata(hdev, wacom);
+       wacom->hdev = hdev;
+
+       /* ask for the report descriptor to be loaded by HID */
+       error = hid_parse(hdev);
+       if (error) {
+               hid_err(hdev, "parse failed\n");
+               goto fail1;
+       }
+
        wacom_wac = &wacom->wacom_wac;
-       wacom_wac->features = *((struct wacom_features *)id->driver_info);
+       wacom_wac->features = *((struct wacom_features *)id->driver_data);
        features = &wacom_wac->features;
+       features->pktlen = wacom_compute_pktlen(hdev);
        if (features->pktlen > WACOM_PKGLEN_MAX) {
                error = -EINVAL;
                goto fail1;
        }
 
-       wacom_wac->data = usb_alloc_coherent(dev, WACOM_PKGLEN_MAX,
-                                            GFP_KERNEL, &wacom->data_dma);
-       if (!wacom_wac->data) {
-               error = -ENOMEM;
+       if (features->check_for_hid_type && features->hid_type != hdev->type) {
+               error = -ENODEV;
                goto fail1;
        }
 
-       wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
-       if (!wacom->irq) {
-               error = -ENOMEM;
-               goto fail2;
-       }
-
        wacom->usbdev = dev;
        wacom->intf = intf;
        mutex_init(&wacom->lock);
        INIT_WORK(&wacom->work, wacom_wireless_work);
-       usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
-       strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
-
-       endpoint = &intf->cur_altsetting->endpoint[0].desc;
 
        /* set the default size in case we do not get them from hid */
        wacom_set_default_phy(features);
 
        /* Retrieve the physical and logical size for touch devices */
-       error = wacom_retrieve_hid_descriptor(intf, features);
-       if (error)
-               goto fail3;
+       wacom_retrieve_hid_descriptor(hdev, features);
 
        /*
         * Intuos5 has no useful data about its touch interface in its
-        * HID descriptor. If this is the touch interface (wMaxPacketSize
+        * HID descriptor. If this is the touch interface (PacketSize
         * of WACOM_PKGLEN_BBTOUCH3), override the table values.
         */
        if (features->type >= INTUOS5S && features->type <= INTUOSHT) {
-               if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) {
+               if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
                        features->device_type = BTN_TOOL_FINGER;
-                       features->pktlen = WACOM_PKGLEN_BBTOUCH3;
 
                        features->x_max = 4096;
                        features->y_max = 4096;
@@ -1353,20 +1300,35 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
                }
        }
 
+       /*
+        * Same thing for Bamboo 3rd gen.
+        */
+       if ((features->type == BAMBOO_PT) &&
+           (features->pktlen == WACOM_PKGLEN_BBTOUCH3) &&
+           (features->device_type == BTN_TOOL_PEN)) {
+               features->device_type = BTN_TOOL_FINGER;
+
+               features->x_max = 4096;
+               features->y_max = 4096;
+       }
+
+       if (hdev->bus == BUS_BLUETOOTH)
+               features->quirks |= WACOM_QUIRK_BATTERY;
+
        wacom_setup_device_quirks(features);
 
        /* set unit to "100th of a mm" for devices not reported by HID */
        if (!features->unit) {
                features->unit = 0x11;
-               features->unitExpo = 16 - 3;
+               features->unitExpo = -3;
        }
        wacom_calculate_res(features);
 
        strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
+       snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name),
+               "%s Pad", features->name);
 
        if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
-               struct usb_device *other_dev;
-
                /* Append the device type to the name */
                if (features->device_type != BTN_TOOL_FINGER)
                        strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
@@ -1375,43 +1337,49 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
                else
                        strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
 
-               other_dev = wacom_get_sibling(dev, features->oVid, features->oPid);
-               if (other_dev == NULL || wacom_get_usbdev_data(other_dev) == NULL)
-                       other_dev = dev;
-               error = wacom_add_shared_data(wacom_wac, other_dev);
+               error = wacom_add_shared_data(hdev);
                if (error)
-                       goto fail3;
+                       goto fail1;
        }
 
-       usb_fill_int_urb(wacom->irq, dev,
-                        usb_rcvintpipe(dev, endpoint->bEndpointAddress),
-                        wacom_wac->data, features->pktlen,
-                        wacom_sys_irq, wacom, endpoint->bInterval);
-       wacom->irq->transfer_dma = wacom->data_dma;
-       wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
        error = wacom_initialize_leds(wacom);
        if (error)
-               goto fail4;
+               goto fail2;
+
+       if (!(features->quirks & WACOM_QUIRK_MONITOR) &&
+            (features->quirks & WACOM_QUIRK_BATTERY)) {
+               error = wacom_initialize_battery(wacom);
+               if (error)
+                       goto fail3;
+       }
 
        if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
-               error = wacom_register_input(wacom);
+               error = wacom_register_inputs(wacom);
                if (error)
-                       goto fail5;
+                       goto fail4;
        }
 
-       /* Note that if query fails it is not a hard failure */
-       wacom_query_tablet_data(intf, features);
+       if (hdev->bus == BUS_BLUETOOTH) {
+               error = device_create_file(&hdev->dev, &dev_attr_speed);
+               if (error)
+                       hid_warn(hdev,
+                                "can't create sysfs speed attribute err: %d\n",
+                                error);
+       }
 
-       usb_set_intfdata(intf, wacom);
+       /* Note that if query fails it is not a hard failure */
+       wacom_query_tablet_data(hdev, features);
 
-       if (features->quirks & WACOM_QUIRK_MONITOR) {
-               if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
-                       error = -EIO;
-                       goto fail5;
-               }
+       /* Regular HID work starts now */
+       error = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+       if (error) {
+               hid_err(hdev, "hw start failed\n");
+               goto fail5;
        }
 
+       if (features->quirks & WACOM_QUIRK_MONITOR)
+               error = hid_hw_open(hdev);
+
        if (wacom_wac->features.type == INTUOSHT && wacom_wac->features.touch_max) {
                if (wacom_wac->features.device_type == BTN_TOOL_FINGER)
                        wacom_wac->shared->touch_input = wacom_wac->input;
@@ -1419,79 +1387,70 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 
        return 0;
 
- fail5: wacom_destroy_leds(wacom);
- fail4:        wacom_remove_shared_data(wacom_wac);
- fail3:        usb_free_urb(wacom->irq);
- fail2:        usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
+ fail5:        if (hdev->bus == BUS_BLUETOOTH)
+               device_remove_file(&hdev->dev, &dev_attr_speed);
+       wacom_unregister_inputs(wacom);
+ fail4:        wacom_destroy_battery(wacom);
+ fail3:        wacom_destroy_leds(wacom);
+ fail2:        wacom_remove_shared_data(wacom_wac);
  fail1:        kfree(wacom);
+       hid_set_drvdata(hdev, NULL);
        return error;
 }
 
-static void wacom_disconnect(struct usb_interface *intf)
+static void wacom_remove(struct hid_device *hdev)
 {
-       struct wacom *wacom = usb_get_intfdata(intf);
+       struct wacom *wacom = hid_get_drvdata(hdev);
 
-       usb_set_intfdata(intf, NULL);
+       hid_hw_stop(hdev);
 
-       usb_kill_urb(wacom->irq);
        cancel_work_sync(&wacom->work);
-       if (wacom->wacom_wac.input)
-               input_unregister_device(wacom->wacom_wac.input);
+       wacom_unregister_inputs(wacom);
+       if (hdev->bus == BUS_BLUETOOTH)
+               device_remove_file(&hdev->dev, &dev_attr_speed);
        wacom_destroy_battery(wacom);
        wacom_destroy_leds(wacom);
-       usb_free_urb(wacom->irq);
-       usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
-                       wacom->wacom_wac.data, wacom->data_dma);
        wacom_remove_shared_data(&wacom->wacom_wac);
-       kfree(wacom);
-}
-
-static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
-{
-       struct wacom *wacom = usb_get_intfdata(intf);
-
-       mutex_lock(&wacom->lock);
-       usb_kill_urb(wacom->irq);
-       mutex_unlock(&wacom->lock);
 
-       return 0;
+       hid_set_drvdata(hdev, NULL);
+       kfree(wacom);
 }
 
-static int wacom_resume(struct usb_interface *intf)
+static int wacom_resume(struct hid_device *hdev)
 {
-       struct wacom *wacom = usb_get_intfdata(intf);
+       struct wacom *wacom = hid_get_drvdata(hdev);
        struct wacom_features *features = &wacom->wacom_wac.features;
-       int rv = 0;
 
        mutex_lock(&wacom->lock);
 
        /* switch to wacom mode first */
-       wacom_query_tablet_data(intf, features);
+       wacom_query_tablet_data(hdev, features);
        wacom_led_control(wacom);
 
-       if ((wacom->open || (features->quirks & WACOM_QUIRK_MONITOR)) &&
-           usb_submit_urb(wacom->irq, GFP_NOIO) < 0)
-               rv = -EIO;
-
        mutex_unlock(&wacom->lock);
 
-       return rv;
+       return 0;
 }
 
-static int wacom_reset_resume(struct usb_interface *intf)
+static int wacom_reset_resume(struct hid_device *hdev)
 {
-       return wacom_resume(intf);
+       return wacom_resume(hdev);
 }
 
-static struct usb_driver wacom_driver = {
+static struct hid_driver wacom_driver = {
        .name =         "wacom",
        .id_table =     wacom_ids,
        .probe =        wacom_probe,
-       .disconnect =   wacom_disconnect,
-       .suspend =      wacom_suspend,
+       .remove =       wacom_remove,
+#ifdef CONFIG_PM
        .resume =       wacom_resume,
        .reset_resume = wacom_reset_resume,
-       .supports_autosuspend = 1,
+#endif
+       .raw_event =    wacom_raw_event,
 };
+module_hid_driver(wacom_driver);
 
-module_usb_driver(wacom_driver);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
similarity index 74%
rename from drivers/input/tablet/wacom_wac.c
rename to drivers/hid/wacom_wac.c
index 977d05cd9e2ea707c08c5eb6d3c9a4fd1a07adae..d4a2d533a444dd5c78b4cf2b834419b61dc9127d 100644 (file)
 #define WACOM_INTUOS_RES       100
 #define WACOM_INTUOS3_RES      200
 
-/* Scale factor relating reported contact size to logical contact area.
+/*
+ * Scale factor relating reported contact size to logical contact area.
  * 2^14/pi is a good approximation on Intuos5 and 3rd-gen Bamboo
  */
 #define WACOM_CONTACT_AREA_SCALE 2607
 
+/*
+ * Percent of battery capacity for Graphire.
+ * 8th value means AC online and show 100% capacity.
+ */
+static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
+
+/*
+ * Percent of battery capacity for Intuos4 WL, AC has a separate bit.
+ */
+static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
+
 static int wacom_penpartner_irq(struct wacom_wac *wacom)
 {
        unsigned char *data = wacom->data;
@@ -217,17 +229,13 @@ static int wacom_dtus_irq(struct wacom_wac *wacom)
                        "%s: received unknown report #%d", __func__, data[0]);
                return 0;
        } else if (data[0] == WACOM_REPORT_DTUSPAD) {
+               input = wacom->pad_input;
                input_report_key(input, BTN_0, (data[1] & 0x01));
                input_report_key(input, BTN_1, (data[1] & 0x02));
                input_report_key(input, BTN_2, (data[1] & 0x04));
                input_report_key(input, BTN_3, (data[1] & 0x08));
                input_report_abs(input, ABS_MISC,
                                 data[1] & 0x0f ? PAD_DEVICE_ID : 0);
-               /*
-                * Serial number is required when expresskeys are
-                * reported through pen interface.
-                */
-               input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
                return 1;
        } else {
                prox = data[1] & 0x80;
@@ -257,7 +265,6 @@ static int wacom_dtus_irq(struct wacom_wac *wacom)
                        wacom->id[0] = 0;
                input_report_key(input, wacom->tool[0], prox);
                input_report_abs(input, ABS_MISC, wacom->id[0]);
-               input_event(input, EV_MSC, MSC_SERIAL, 1);
                return 1;
        }
 }
@@ -267,11 +274,20 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
        struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        struct input_dev *input = wacom->input;
+       struct input_dev *pad_input = wacom->pad_input;
+       int battery_capacity, ps_connected;
        int prox;
        int rw = 0;
        int retval = 0;
 
-       if (data[0] != WACOM_REPORT_PENABLED) {
+       if (features->type == GRAPHIRE_BT) {
+               if (data[0] != WACOM_REPORT_PENABLED_BT) {
+                       dev_dbg(input->dev.parent,
+                               "%s: received unknown report #%d\n", __func__,
+                               data[0]);
+                       goto exit;
+               }
+       } else if (data[0] != WACOM_REPORT_PENABLED) {
                dev_dbg(input->dev.parent,
                        "%s: received unknown report #%d\n", __func__, data[0]);
                goto exit;
@@ -305,7 +321,12 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
                input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
                input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
                if (wacom->tool[0] != BTN_TOOL_MOUSE) {
-                       input_report_abs(input, ABS_PRESSURE, data[6] | ((data[7] & 0x03) << 8));
+                       if (features->type == GRAPHIRE_BT)
+                               input_report_abs(input, ABS_PRESSURE, data[6] |
+                                       (((__u16) (data[1] & 0x08)) << 5));
+                       else
+                               input_report_abs(input, ABS_PRESSURE, data[6] |
+                                       ((data[7] & 0x03) << 8));
                        input_report_key(input, BTN_TOUCH, data[1] & 0x01);
                        input_report_key(input, BTN_STYLUS, data[1] & 0x02);
                        input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
@@ -316,6 +337,20 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
                                        features->type == WACOM_MO) {
                                input_report_abs(input, ABS_DISTANCE, data[6] & 0x3f);
                                rw = (data[7] & 0x04) - (data[7] & 0x03);
+                       } else if (features->type == GRAPHIRE_BT) {
+                               /* Compute distance between mouse and tablet */
+                               rw = 44 - (data[6] >> 2);
+                               rw = clamp_val(rw, 0, 31);
+                               input_report_abs(input, ABS_DISTANCE, rw);
+                               if (((data[1] >> 5) & 3) == 2) {
+                                       /* Mouse with wheel */
+                                       input_report_key(input, BTN_MIDDLE,
+                                                       data[1] & 0x04);
+                                       rw = (data[6] & 0x01) ? -1 :
+                                               (data[6] & 0x02) ? 1 : 0;
+                               } else {
+                                       rw = 0;
+                               }
                        } else {
                                input_report_abs(input, ABS_DISTANCE, data[7] & 0x3f);
                                rw = -(signed char)data[6];
@@ -327,7 +362,6 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
                        wacom->id[0] = 0;
                input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
                input_report_key(input, wacom->tool[0], prox);
-               input_event(input, EV_MSC, MSC_SERIAL, 1);
                input_sync(input); /* sync last event */
        }
 
@@ -337,14 +371,13 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
                prox = data[7] & 0xf8;
                if (prox || wacom->id[1]) {
                        wacom->id[1] = PAD_DEVICE_ID;
-                       input_report_key(input, BTN_BACK, (data[7] & 0x40));
-                       input_report_key(input, BTN_FORWARD, (data[7] & 0x80));
+                       input_report_key(pad_input, BTN_BACK, (data[7] & 0x40));
+                       input_report_key(pad_input, BTN_FORWARD, (data[7] & 0x80));
                        rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
-                       input_report_rel(input, REL_WHEEL, rw);
+                       input_report_rel(pad_input, REL_WHEEL, rw);
                        if (!prox)
                                wacom->id[1] = 0;
-                       input_report_abs(input, ABS_MISC, wacom->id[1]);
-                       input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
+                       input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
                        retval = 1;
                }
                break;
@@ -353,19 +386,43 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
                prox = (data[7] & 0xf8) || data[8];
                if (prox || wacom->id[1]) {
                        wacom->id[1] = PAD_DEVICE_ID;
-                       input_report_key(input, BTN_BACK, (data[7] & 0x08));
-                       input_report_key(input, BTN_LEFT, (data[7] & 0x20));
-                       input_report_key(input, BTN_FORWARD, (data[7] & 0x10));
-                       input_report_key(input, BTN_RIGHT, (data[7] & 0x40));
-                       input_report_abs(input, ABS_WHEEL, (data[8] & 0x7f));
+                       input_report_key(pad_input, BTN_BACK, (data[7] & 0x08));
+                       input_report_key(pad_input, BTN_LEFT, (data[7] & 0x20));
+                       input_report_key(pad_input, BTN_FORWARD, (data[7] & 0x10));
+                       input_report_key(pad_input, BTN_RIGHT, (data[7] & 0x40));
+                       input_report_abs(pad_input, ABS_WHEEL, (data[8] & 0x7f));
+                       if (!prox)
+                               wacom->id[1] = 0;
+                       input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
+                       retval = 1;
+               }
+               break;
+       case GRAPHIRE_BT:
+               prox = data[7] & 0x03;
+               if (prox || wacom->id[1]) {
+                       wacom->id[1] = PAD_DEVICE_ID;
+                       input_report_key(pad_input, BTN_0, (data[7] & 0x02));
+                       input_report_key(pad_input, BTN_1, (data[7] & 0x01));
                        if (!prox)
                                wacom->id[1] = 0;
-                       input_report_abs(input, ABS_MISC, wacom->id[1]);
-                       input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
+                       input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
                        retval = 1;
                }
                break;
        }
+
+       /* Store current battery capacity and power supply state */
+       if (features->type == GRAPHIRE_BT) {
+               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);
+               }
+       }
 exit:
        return retval;
 }
@@ -584,6 +641,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
 
        /* pad packets. Works as a second tool and is always in prox */
        if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) {
+               input = wacom->pad_input;
                if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
                        input_report_key(input, BTN_0, (data[2] & 0x01));
                        input_report_key(input, BTN_1, (data[3] & 0x01));
@@ -773,7 +831,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                                input_report_abs(input, ABS_MISC, 0);
                        }
                }
-               input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
                 return 1;
        }
 
@@ -901,6 +958,58 @@ static int int_dist(int x1, int y1, int x2, int y2)
        return int_sqrt(x*x + y*y);
 }
 
+static void wacom_intuos_bt_process_data(struct wacom_wac *wacom,
+               unsigned char *data)
+{
+       memcpy(wacom->data, data, 10);
+       wacom_intuos_irq(wacom);
+
+       input_sync(wacom->input);
+       if (wacom->pad_input)
+               input_sync(wacom->pad_input);
+}
+
+static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
+{
+       unsigned char data[WACOM_PKGLEN_MAX];
+       int i = 1;
+       unsigned power_raw, battery_capacity, bat_charging, ps_connected;
+
+       memcpy(data, wacom->data, len);
+
+       switch (data[0]) {
+       case 0x04:
+               wacom_intuos_bt_process_data(wacom, data + i);
+               i += 10;
+               /* fall through */
+       case 0x03:
+               wacom_intuos_bt_process_data(wacom, data + i);
+               i += 10;
+               wacom_intuos_bt_process_data(wacom, data + i);
+               i += 10;
+               power_raw = data[i];
+               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);
+               }
+
+               break;
+       default:
+               dev_dbg(wacom->input->dev.parent,
+                               "Unknown report: %d,%d size:%zu\n",
+                               data[0], data[1], len);
+               return 0;
+       }
+       return 0;
+}
+
 static int wacom_24hdt_irq(struct wacom_wac *wacom)
 {
        struct input_dev *input = wacom->input;
@@ -1093,7 +1202,7 @@ static int wacom_tpc_pen(struct wacom_wac *wacom)
                input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
                input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
                input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
-               input_report_abs(input, ABS_PRESSURE, ((data[7] & 0x03) << 8) | data[6]);
+               input_report_abs(input, ABS_PRESSURE, ((data[7] & 0x07) << 8) | data[6]);
                input_report_key(input, BTN_TOUCH, data[1] & 0x05);
                input_report_key(input, wacom->tool[0], prox);
                return 1;
@@ -1143,6 +1252,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
 {
        struct wacom_features *features = &wacom->features;
        struct input_dev *input = wacom->input;
+       struct input_dev *pad_input = wacom->pad_input;
        unsigned char *data = wacom->data;
        int i;
 
@@ -1177,14 +1287,12 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
 
        input_mt_report_pointer_emulation(input, true);
 
-       input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
-       input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
-       input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);
-       input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0);
-
-       input_sync(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);
 
-       return 0;
+       return 1;
 }
 
 static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
@@ -1232,7 +1340,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
 
 static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
 {
-       struct input_dev *input = wacom->input;
+       struct input_dev *input = wacom->pad_input;
        struct wacom_features *features = &wacom->features;
 
        if (features->type == INTUOSHT) {
@@ -1269,9 +1377,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
        }
        input_mt_report_pointer_emulation(input, true);
 
-       input_sync(input);
-
-       return 0;
+       return 1;
 }
 
 static int wacom_bpt_pen(struct wacom_wac *wacom)
@@ -1375,7 +1481,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
 
        connected = data[1] & 0x01;
        if (connected) {
-               int pid, battery;
+               int pid, battery, ps_connected;
 
                if ((wacom->shared->type == INTUOSHT) &&
                                wacom->shared->touch_max) {
@@ -1385,17 +1491,29 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
                }
 
                pid = get_unaligned_be16(&data[6]);
-               battery = data[5] & 0x3f;
+               battery = (data[5] & 0x3f) * 100 / 31;
+               ps_connected = !!(data[5] & 0x80);
                if (wacom->pid != pid) {
                        wacom->pid = pid;
                        wacom_schedule_work(wacom);
                }
-               wacom->battery_capacity = battery;
+
+               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);
+               }
        } 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;
        }
 
        return 0;
@@ -1416,6 +1534,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 
        case WACOM_G4:
        case GRAPHIRE:
+       case GRAPHIRE_BT:
        case WACOM_MO:
                sync = wacom_graphire_irq(wacom_wac);
                break;
@@ -1450,6 +1569,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
                sync = wacom_intuos_irq(wacom_wac);
                break;
 
+       case INTUOS4WL:
+               sync = wacom_intuos_bt_irq(wacom_wac, len);
+               break;
+
        case WACOM_24HDT:
                sync = wacom_24hdt_irq(wacom_wac);
                break;
@@ -1489,8 +1612,11 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
                break;
        }
 
-       if (sync)
+       if (sync) {
                input_sync(wacom_wac->input);
+               if (wacom_wac->pad_input)
+                       input_sync(wacom_wac->pad_input);
+       }
 }
 
 static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
@@ -1565,8 +1691,10 @@ void wacom_setup_device_quirks(struct wacom_features *features)
                features->quirks |= WACOM_QUIRK_NO_INPUT;
 
                /* must be monitor interface if no device_type set */
-               if (!features->device_type)
+               if (!features->device_type) {
                        features->quirks |= WACOM_QUIRK_MONITOR;
+                       features->quirks |= WACOM_QUIRK_BATTERY;
+               }
        }
 }
 
@@ -1615,7 +1743,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
                                   struct wacom_wac *wacom_wac)
 {
        struct wacom_features *features = &wacom_wac->features;
-       int i;
 
        input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 
@@ -1630,10 +1757,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
                /* fall through */
 
        case WACOM_G4:
-               input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
-
-               __set_bit(BTN_BACK, input_dev->keybit);
-               __set_bit(BTN_FORWARD, input_dev->keybit);
                /* fall through */
 
        case GRAPHIRE:
@@ -1652,62 +1775,42 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
                __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
                break;
 
-       case WACOM_24HD:
-               __set_bit(BTN_A, input_dev->keybit);
-               __set_bit(BTN_B, input_dev->keybit);
-               __set_bit(BTN_C, input_dev->keybit);
-               __set_bit(BTN_X, input_dev->keybit);
-               __set_bit(BTN_Y, input_dev->keybit);
-               __set_bit(BTN_Z, input_dev->keybit);
+       case GRAPHIRE_BT:
+               __clear_bit(ABS_MISC, input_dev->absbit);
+               input_set_abs_params(input_dev, ABS_DISTANCE, 0,
+                                             features->distance_max,
+                                             0, 0);
 
-               for (i = 6; i < 10; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
+               input_set_capability(input_dev, EV_REL, REL_WHEEL);
 
-               __set_bit(KEY_PROG1, input_dev->keybit);
-               __set_bit(KEY_PROG2, input_dev->keybit);
-               __set_bit(KEY_PROG3, input_dev->keybit);
+               __set_bit(BTN_LEFT, input_dev->keybit);
+               __set_bit(BTN_RIGHT, input_dev->keybit);
+               __set_bit(BTN_MIDDLE, input_dev->keybit);
+
+               __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+               __set_bit(BTN_TOOL_PEN, input_dev->keybit);
+               __set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
+               __set_bit(BTN_STYLUS, input_dev->keybit);
+               __set_bit(BTN_STYLUS2, input_dev->keybit);
 
+               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+               break;
+
+       case WACOM_24HD:
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
                /* fall through */
 
        case DTK:
-               for (i = 0; i < 6; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
-
                __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
 
                wacom_setup_cintiq(wacom_wac);
                break;
 
        case WACOM_22HD:
-               __set_bit(KEY_PROG1, input_dev->keybit);
-               __set_bit(KEY_PROG2, input_dev->keybit);
-               __set_bit(KEY_PROG3, input_dev->keybit);
-               /* fall through */
-
        case WACOM_21UX2:
-               __set_bit(BTN_A, input_dev->keybit);
-               __set_bit(BTN_B, input_dev->keybit);
-               __set_bit(BTN_C, input_dev->keybit);
-               __set_bit(BTN_X, input_dev->keybit);
-               __set_bit(BTN_Y, input_dev->keybit);
-               __set_bit(BTN_Z, input_dev->keybit);
-               __set_bit(BTN_BASE, input_dev->keybit);
-               __set_bit(BTN_BASE2, input_dev->keybit);
-               /* fall through */
-
        case WACOM_BEE:
-               __set_bit(BTN_8, input_dev->keybit);
-               __set_bit(BTN_9, input_dev->keybit);
-               /* fall through */
-
        case CINTIQ:
-               for (i = 0; i < 8; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
-
-               input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
-               input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
 
                __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
@@ -1716,9 +1819,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
                break;
 
        case WACOM_13HD:
-               for (i = 0; i < 9; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
-
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
                wacom_setup_cintiq(wacom_wac);
@@ -1726,21 +1826,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 
        case INTUOS3:
        case INTUOS3L:
-               __set_bit(BTN_4, input_dev->keybit);
-               __set_bit(BTN_5, input_dev->keybit);
-               __set_bit(BTN_6, input_dev->keybit);
-               __set_bit(BTN_7, input_dev->keybit);
-
-               input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
-               /* fall through */
-
        case INTUOS3S:
-               __set_bit(BTN_0, input_dev->keybit);
-               __set_bit(BTN_1, input_dev->keybit);
-               __set_bit(BTN_2, input_dev->keybit);
-               __set_bit(BTN_3, input_dev->keybit);
-
-               input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                /* fall through */
 
@@ -1754,20 +1840,11 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
        case INTUOS5L:
        case INTUOSPM:
        case INTUOSPL:
-               if (features->device_type == BTN_TOOL_PEN) {
-                       __set_bit(BTN_7, input_dev->keybit);
-                       __set_bit(BTN_8, input_dev->keybit);
-               }
-               /* fall through */
-
        case INTUOS5S:
        case INTUOSPS:
                __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
 
                if (features->device_type == BTN_TOOL_PEN) {
-                       for (i = 0; i < 7; i++)
-                               __set_bit(BTN_0 + i, input_dev->keybit);
-
                        input_set_abs_params(input_dev, ABS_DISTANCE, 0,
                                              features->distance_max,
                                              0, 0);
@@ -1787,15 +1864,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
                break;
 
        case INTUOS4:
+       case INTUOS4WL:
        case INTUOS4L:
-               __set_bit(BTN_7, input_dev->keybit);
-               __set_bit(BTN_8, input_dev->keybit);
-               /* fall through */
-
        case INTUOS4S:
-               for (i = 0; i < 7; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
-
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                wacom_setup_intuos(wacom_wac);
 
@@ -1839,11 +1910,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
        case DTUS:
        case PL:
        case DTU:
-               if (features->type == DTUS) {
-                       input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
-                       for (i = 0; i < 4; i++)
-                               __set_bit(BTN_0 + i, input_dev->keybit);
-               }
                __set_bit(BTN_TOOL_PEN, input_dev->keybit);
                __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
                __set_bit(BTN_STYLUS, input_dev->keybit);
@@ -1877,11 +1943,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 
                if (features->device_type == BTN_TOOL_FINGER) {
 
-                       __set_bit(BTN_LEFT, input_dev->keybit);
-                       __set_bit(BTN_FORWARD, input_dev->keybit);
-                       __set_bit(BTN_BACK, input_dev->keybit);
-                       __set_bit(BTN_RIGHT, input_dev->keybit);
-
                        if (features->touch_max) {
                                /* touch interface */
                                unsigned int flags = INPUT_MT_POINTER;
@@ -1919,449 +1980,629 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
                break;
 
        case CINTIQ_HYBRID:
+               input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+               __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
+               wacom_setup_cintiq(wacom_wac);
+               break;
+       }
+       return 0;
+}
+
+int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
+                                  struct wacom_wac *wacom_wac)
+{
+       struct wacom_features *features = &wacom_wac->features;
+       int i;
+
+       input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+
+       /* kept for making legacy xf86-input-wacom working with the wheels */
+       __set_bit(ABS_MISC, input_dev->absbit);
+
+       /* kept for making legacy xf86-input-wacom accepting the pad */
+       input_set_abs_params(input_dev, ABS_X, 0, 1, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, 1, 0, 0);
+
+       switch (features->type) {
+       case GRAPHIRE_BT:
+               __set_bit(BTN_0, input_dev->keybit);
                __set_bit(BTN_1, input_dev->keybit);
-               __set_bit(BTN_2, input_dev->keybit);
-               __set_bit(BTN_3, input_dev->keybit);
-               __set_bit(BTN_4, input_dev->keybit);
+               break;
+
+       case WACOM_MO:
+               __set_bit(BTN_BACK, input_dev->keybit);
+               __set_bit(BTN_LEFT, input_dev->keybit);
+               __set_bit(BTN_FORWARD, input_dev->keybit);
+               __set_bit(BTN_RIGHT, input_dev->keybit);
+               input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
+               break;
+
+       case WACOM_G4:
+               __set_bit(BTN_BACK, input_dev->keybit);
+               __set_bit(BTN_LEFT, input_dev->keybit);
+               __set_bit(BTN_FORWARD, input_dev->keybit);
+               __set_bit(BTN_RIGHT, input_dev->keybit);
+               input_set_capability(input_dev, EV_REL, REL_WHEEL);
+               break;
+
+       case WACOM_24HD:
+               __set_bit(BTN_A, input_dev->keybit);
+               __set_bit(BTN_B, input_dev->keybit);
+               __set_bit(BTN_C, input_dev->keybit);
+               __set_bit(BTN_X, input_dev->keybit);
+               __set_bit(BTN_Y, input_dev->keybit);
+               __set_bit(BTN_Z, input_dev->keybit);
+
+               for (i = 0; i < 10; i++)
+                       __set_bit(BTN_0 + i, input_dev->keybit);
+
+               __set_bit(KEY_PROG1, input_dev->keybit);
+               __set_bit(KEY_PROG2, input_dev->keybit);
+               __set_bit(KEY_PROG3, input_dev->keybit);
+
+               input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
+               input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
+               break;
+
+       case DTK:
+               for (i = 0; i < 6; i++)
+                       __set_bit(BTN_0 + i, input_dev->keybit);
+
+               break;
+
+       case WACOM_22HD:
+               __set_bit(KEY_PROG1, input_dev->keybit);
+               __set_bit(KEY_PROG2, input_dev->keybit);
+               __set_bit(KEY_PROG3, input_dev->keybit);
+               /* fall through */
+
+       case WACOM_21UX2:
+               __set_bit(BTN_A, input_dev->keybit);
+               __set_bit(BTN_B, input_dev->keybit);
+               __set_bit(BTN_C, input_dev->keybit);
+               __set_bit(BTN_X, input_dev->keybit);
+               __set_bit(BTN_Y, input_dev->keybit);
+               __set_bit(BTN_Z, input_dev->keybit);
+               __set_bit(BTN_BASE, input_dev->keybit);
+               __set_bit(BTN_BASE2, input_dev->keybit);
+               /* fall through */
+
+       case WACOM_BEE:
+               __set_bit(BTN_8, input_dev->keybit);
+               __set_bit(BTN_9, input_dev->keybit);
+               /* fall through */
+
+       case CINTIQ:
+               for (i = 0; i < 8; i++)
+                       __set_bit(BTN_0 + i, input_dev->keybit);
+
+               input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
+               input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
+               break;
+
+       case WACOM_13HD:
+               for (i = 0; i < 9; i++)
+                       __set_bit(BTN_0 + i, input_dev->keybit);
 
+               input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
+               break;
+
+       case INTUOS3:
+       case INTUOS3L:
+               __set_bit(BTN_4, input_dev->keybit);
                __set_bit(BTN_5, input_dev->keybit);
                __set_bit(BTN_6, input_dev->keybit);
                __set_bit(BTN_7, input_dev->keybit);
-               __set_bit(BTN_8, input_dev->keybit);
+
+               input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
+               /* fall through */
+
+       case INTUOS3S:
                __set_bit(BTN_0, input_dev->keybit);
+               __set_bit(BTN_1, input_dev->keybit);
+               __set_bit(BTN_2, input_dev->keybit);
+               __set_bit(BTN_3, input_dev->keybit);
 
-               input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
-               __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+               input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
+               break;
+
+       case INTUOS5:
+       case INTUOS5L:
+       case INTUOSPM:
+       case INTUOSPL:
+               __set_bit(BTN_7, input_dev->keybit);
+               __set_bit(BTN_8, input_dev->keybit);
+               /* fall through */
+
+       case INTUOS5S:
+       case INTUOSPS:
+               /* touch interface does not have the pad device */
+               if (features->device_type != BTN_TOOL_PEN)
+                       return 1;
+
+               for (i = 0; i < 7; i++)
+                       __set_bit(BTN_0 + i, input_dev->keybit);
+
+               input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
+               break;
+
+       case INTUOS4WL:
+               /*
+                * For Bluetooth devices, the udev rule does not work correctly
+                * for pads unless we add a stylus capability, which forces
+                * ID_INPUT_TABLET to be set.
+                */
+               __set_bit(BTN_STYLUS, input_dev->keybit);
+               /* fall through */
+
+       case INTUOS4:
+       case INTUOS4L:
+               __set_bit(BTN_7, input_dev->keybit);
+               __set_bit(BTN_8, input_dev->keybit);
+               /* fall through */
+
+       case INTUOS4S:
+               for (i = 0; i < 7; i++)
+                       __set_bit(BTN_0 + i, input_dev->keybit);
+
+               input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
+               break;
+
+       case CINTIQ_HYBRID:
+               for (i = 0; i < 9; i++)
+                       __set_bit(BTN_0 + i, input_dev->keybit);
 
-               wacom_setup_cintiq(wacom_wac);
                break;
+
+       case DTUS:
+               for (i = 0; i < 4; i++)
+                       __set_bit(BTN_0 + i, input_dev->keybit);
+               break;
+
+       case INTUOSHT:
+       case BAMBOO_PT:
+               /* pad device is on the touch interface */
+               if (features->device_type != BTN_TOOL_FINGER)
+                       return 1;
+
+               __clear_bit(ABS_MISC, input_dev->absbit);
+
+               __set_bit(BTN_LEFT, input_dev->keybit);
+               __set_bit(BTN_FORWARD, input_dev->keybit);
+               __set_bit(BTN_BACK, input_dev->keybit);
+               __set_bit(BTN_RIGHT, input_dev->keybit);
+
+               break;
+
+       default:
+               /* no pad supported */
+               return 1;
        }
        return 0;
 }
 
 static const struct wacom_features wacom_features_0x00 =
-       { "Wacom Penpartner",     WACOM_PKGLEN_PENPRTN,    5040,  3780,  255,
-         0, PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
+       { "Wacom Penpartner", 5040, 3780, 255, 0,
+         PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
 static const struct wacom_features wacom_features_0x10 =
-       { "Wacom Graphire",       WACOM_PKGLEN_GRAPHIRE,  10206,  7422,  511,
-         63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+       { "Wacom Graphire", 10206, 7422, 511, 63,
+         GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+static const struct wacom_features wacom_features_0x81 =
+       { "Wacom Graphire BT", 16704, 12064, 511, 32,
+         GRAPHIRE_BT, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
 static const struct wacom_features wacom_features_0x11 =
-       { "Wacom Graphire2 4x5",  WACOM_PKGLEN_GRAPHIRE,  10206,  7422,  511,
-         63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+       { "Wacom Graphire2 4x5", 10206, 7422, 511, 63,
+         GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
 static const struct wacom_features wacom_features_0x12 =
-       { "Wacom Graphire2 5x7",  WACOM_PKGLEN_GRAPHIRE,  13918, 10206,  511,
-         63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+       { "Wacom Graphire2 5x7", 13918, 10206, 511, 63,
+         GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
 static const struct wacom_features wacom_features_0x13 =
-       { "Wacom Graphire3",      WACOM_PKGLEN_GRAPHIRE,  10208,  7424,  511,
-         63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+       { "Wacom Graphire3", 10208, 7424, 511, 63,
+         GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
 static const struct wacom_features wacom_features_0x14 =
-       { "Wacom Graphire3 6x8",  WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511,
-         63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+       { "Wacom Graphire3 6x8", 16704, 12064, 511, 63,
+         GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
 static const struct wacom_features wacom_features_0x15 =
-       { "Wacom Graphire4 4x5",  WACOM_PKGLEN_GRAPHIRE,  10208,  7424,  511,
-         63, WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+       { "Wacom Graphire4 4x5", 10208, 7424, 511, 63,
+         WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
 static const struct wacom_features wacom_features_0x16 =
-       { "Wacom Graphire4 6x8",  WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511,
-         63, WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+       { "Wacom Graphire4 6x8", 16704, 12064, 511, 63,
+         WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
 static const struct wacom_features wacom_features_0x17 =
-       { "Wacom BambooFun 4x5",  WACOM_PKGLEN_BBFUN,     14760,  9225,  511,
-         63, WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom BambooFun 4x5", 14760, 9225, 511, 63,
+         WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x18 =
-       { "Wacom BambooFun 6x8",  WACOM_PKGLEN_BBFUN,     21648, 13530,  511,
-         63, WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom BambooFun 6x8", 21648, 13530, 511, 63,
+         WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x19 =
-       { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511,
-         63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+       { "Wacom Bamboo1 Medium", 16704, 12064, 511, 63,
+         GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
 static const struct wacom_features wacom_features_0x60 =
-       { "Wacom Volito",         WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511,
-         63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
+       { "Wacom Volito", 5104, 3712, 511, 63,
+         GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
 static const struct wacom_features wacom_features_0x61 =
-       { "Wacom PenStation2",    WACOM_PKGLEN_GRAPHIRE,   3250,  2320,  255,
-         63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
+       { "Wacom PenStation2", 3250, 2320, 255, 63,
+         GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
 static const struct wacom_features wacom_features_0x62 =
-       { "Wacom Volito2 4x5",    WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511,
-         63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
+       { "Wacom Volito2 4x5", 5104, 3712, 511, 63,
+         GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
 static const struct wacom_features wacom_features_0x63 =
-       { "Wacom Volito2 2x3",    WACOM_PKGLEN_GRAPHIRE,   3248,  2320,  511,
-         63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
+       { "Wacom Volito2 2x3", 3248, 2320, 511, 63,
+         GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
 static const struct wacom_features wacom_features_0x64 =
-       { "Wacom PenPartner2",    WACOM_PKGLEN_GRAPHIRE,   3250,  2320,  511,
-         63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
+       { "Wacom PenPartner2", 3250, 2320, 511, 63,
+         GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
 static const struct wacom_features wacom_features_0x65 =
-       { "Wacom Bamboo",         WACOM_PKGLEN_BBFUN,     14760,  9225,  511,
-         63, WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Bamboo", 14760, 9225, 511, 63,
+         WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x69 =
-       { "Wacom Bamboo1",        WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511,
-         63, GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
+       { "Wacom Bamboo1", 5104, 3712, 511, 63,
+         GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
 static const struct wacom_features wacom_features_0x6A =
-       { "Wacom Bamboo1 4x6",    WACOM_PKGLEN_GRAPHIRE,  14760,  9225, 1023,
-         63, GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Bamboo1 4x6", 14760, 9225, 1023, 63,
+         GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x6B =
-       { "Wacom Bamboo1 5x8",    WACOM_PKGLEN_GRAPHIRE,  21648, 13530, 1023,
-         63, GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Bamboo1 5x8", 21648, 13530, 1023, 63,
+         GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x20 =
-       { "Wacom Intuos 4x5",     WACOM_PKGLEN_INTUOS,    12700, 10600, 1023,
-         31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Intuos 4x5", 12700, 10600, 1023, 31,
+         INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x21 =
-       { "Wacom Intuos 6x8",     WACOM_PKGLEN_INTUOS,    20320, 16240, 1023,
-         31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Intuos 6x8", 20320, 16240, 1023, 31,
+         INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x22 =
-       { "Wacom Intuos 9x12",    WACOM_PKGLEN_INTUOS,    30480, 24060, 1023,
-         31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Intuos 9x12", 30480, 24060, 1023, 31,
+         INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x23 =
-       { "Wacom Intuos 12x12",   WACOM_PKGLEN_INTUOS,    30480, 31680, 1023,
-         31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Intuos 12x12", 30480, 31680, 1023, 31,
+         INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x24 =
-       { "Wacom Intuos 12x18",   WACOM_PKGLEN_INTUOS,    45720, 31680, 1023,
-         31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Intuos 12x18", 45720, 31680, 1023, 31,
+         INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x30 =
-       { "Wacom PL400",          WACOM_PKGLEN_GRAPHIRE,   5408,  4056,  255,
-         0, PL, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom PL400", 5408, 4056, 255, 0,
+         PL, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0x31 =
-       { "Wacom PL500",          WACOM_PKGLEN_GRAPHIRE,   6144,  4608,  255,
-         0, PL, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom PL500", 6144, 4608, 255, 0,
+         PL, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0x32 =
-       { "Wacom PL600",          WACOM_PKGLEN_GRAPHIRE,   6126,  4604,  255,
-         0, PL, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom PL600", 6126, 4604, 255, 0,
+         PL, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0x33 =
-       { "Wacom PL600SX",        WACOM_PKGLEN_GRAPHIRE,   6260,  5016,  255,
-         0, PL, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom PL600SX", 6260, 5016, 255, 0,
+         PL, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0x34 =
-       { "Wacom PL550",          WACOM_PKGLEN_GRAPHIRE,   6144,  4608,  511,
-         0, PL, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom PL550", 6144, 4608, 511, 0,
+         PL, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0x35 =
-       { "Wacom PL800",          WACOM_PKGLEN_GRAPHIRE,   7220,  5780,  511,
-         0, PL, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom PL800", 7220, 5780, 511, 0,
+         PL, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0x37 =
-       { "Wacom PL700",          WACOM_PKGLEN_GRAPHIRE,   6758,  5406,  511,
-         0, PL, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom PL700", 6758, 5406, 511, 0,
+         PL, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0x38 =
-       { "Wacom PL510",          WACOM_PKGLEN_GRAPHIRE,   6282,  4762,  511,
-         0, PL, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom PL510", 6282, 4762, 511, 0,
+         PL, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0x39 =
-       { "Wacom DTU710",         WACOM_PKGLEN_GRAPHIRE,  34080, 27660,  511,
-         0, PL, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom DTU710", 34080, 27660, 511, 0,
+         PL, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0xC4 =
-       { "Wacom DTF521",         WACOM_PKGLEN_GRAPHIRE,   6282,  4762,  511,
-         0, PL, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom DTF521", 6282, 4762, 511, 0,
+         PL, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0xC0 =
-       { "Wacom DTF720",         WACOM_PKGLEN_GRAPHIRE,   6858,  5506,  511,
-         0, PL, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom DTF720", 6858, 5506, 511, 0,
+         PL, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0xC2 =
-       { "Wacom DTF720a",        WACOM_PKGLEN_GRAPHIRE,   6858,  5506,  511,
-         0, PL, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom DTF720a", 6858, 5506, 511, 0,
+         PL, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0x03 =
-       { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE,  20480, 15360,  511,
-         0, PTU, WACOM_PL_RES, WACOM_PL_RES };
+       { "Wacom Cintiq Partner", 20480, 15360, 511, 0,
+         PTU, WACOM_PL_RES, WACOM_PL_RES };
 static const struct wacom_features wacom_features_0x41 =
-       { "Wacom Intuos2 4x5",    WACOM_PKGLEN_INTUOS,    12700, 10600, 1023,
-         31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Intuos2 4x5", 12700, 10600, 1023, 31,
+         INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x42 =
-       { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023,
-         31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Intuos2 6x8", 20320, 16240, 1023, 31,
+         INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x43 =
-       { "Wacom Intuos2 9x12",   WACOM_PKGLEN_INTUOS,    30480, 24060, 1023,
-         31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Intuos2 9x12", 30480, 24060, 1023, 31,
+         INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x44 =
-       { "Wacom Intuos2 12x12",  WACOM_PKGLEN_INTUOS,    30480, 31680, 1023,
-         31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Intuos2 12x12", 30480, 31680, 1023, 31,
+         INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x45 =
-       { "Wacom Intuos2 12x18",  WACOM_PKGLEN_INTUOS,    45720, 31680, 1023,
-         31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Intuos2 12x18", 45720, 31680, 1023, 31,
+         INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xB0 =
-       { "Wacom Intuos3 4x5",    WACOM_PKGLEN_INTUOS,    25400, 20320, 1023,
-         63, INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos3 4x5", 25400, 20320, 1023, 63,
+         INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xB1 =
-       { "Wacom Intuos3 6x8",    WACOM_PKGLEN_INTUOS,    40640, 30480, 1023,
-         63, INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos3 6x8", 40640, 30480, 1023, 63,
+         INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xB2 =
-       { "Wacom Intuos3 9x12",   WACOM_PKGLEN_INTUOS,    60960, 45720, 1023,
-         63, INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos3 9x12", 60960, 45720, 1023, 63,
+         INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xB3 =
-       { "Wacom Intuos3 12x12",  WACOM_PKGLEN_INTUOS,    60960, 60960, 1023,
-         63, INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos3 12x12", 60960, 60960, 1023, 63,
+         INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xB4 =
-       { "Wacom Intuos3 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 1023,
-         63, INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos3 12x19", 97536, 60960, 1023, 63,
+         INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xB5 =
-       { "Wacom Intuos3 6x11",   WACOM_PKGLEN_INTUOS,    54204, 31750, 1023,
-         63, INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos3 6x11", 54204, 31750, 1023, 63,
+         INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xB7 =
-       { "Wacom Intuos3 4x6",    WACOM_PKGLEN_INTUOS,    31496, 19685, 1023,
-         63, INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos3 4x6", 31496, 19685, 1023, 63,
+         INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xB8 =
-       { "Wacom Intuos4 4x6",    WACOM_PKGLEN_INTUOS,    31496, 19685, 2047,
-         63, INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos4 4x6", 31496, 19685, 2047, 63,
+         INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xB9 =
-       { "Wacom Intuos4 6x9",    WACOM_PKGLEN_INTUOS,    44704, 27940, 2047,
-         63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos4 6x9", 44704, 27940, 2047, 63,
+         INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xBA =
-       { "Wacom Intuos4 8x13",   WACOM_PKGLEN_INTUOS,    65024, 40640, 2047,
-         63, INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos4 8x13", 65024, 40640, 2047, 63,
+         INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xBB =
-       { "Wacom Intuos4 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 2047,
-         63, INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos4 12x19", 97536, 60960, 2047, 63,
+         INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xBC =
-       { "Wacom Intuos4 WL",     WACOM_PKGLEN_INTUOS,    40640, 25400, 2047,
-         63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos4 WL", 40640, 25400, 2047, 63,
+         INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0xBD =
+       { "Wacom Intuos4 WL", 40640, 25400, 2047, 63,
+         INTUOS4WL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0x26 =
-       { "Wacom Intuos5 touch S", WACOM_PKGLEN_INTUOS,  31496, 19685, 2047,
-         63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
-         .touch_max = 16 };
+       { "Wacom Intuos5 touch S", 31496, 19685, 2047, 63,
+         INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 };
 static const struct wacom_features wacom_features_0x27 =
-       { "Wacom Intuos5 touch M", WACOM_PKGLEN_INTUOS,  44704, 27940, 2047,
-         63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
-         .touch_max = 16 };
+       { "Wacom Intuos5 touch M", 44704, 27940, 2047, 63,
+         INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 };
 static const struct wacom_features wacom_features_0x28 =
-       { "Wacom Intuos5 touch L", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047,
-         63, INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
-         .touch_max = 16 };
+       { "Wacom Intuos5 touch L", 65024, 40640, 2047, 63,
+         INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 };
 static const struct wacom_features wacom_features_0x29 =
-       { "Wacom Intuos5 S", WACOM_PKGLEN_INTUOS,  31496, 19685, 2047,
-         63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos5 S", 31496, 19685, 2047, 63,
+         INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0x2A =
-       { "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS,  44704, 27940, 2047,
-         63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Intuos5 M", 44704, 27940, 2047, 63,
+         INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0x314 =
-       { "Wacom Intuos Pro S", WACOM_PKGLEN_INTUOS,  31496, 19685, 2047,
-         63, INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
-         .touch_max = 16 };
+       { "Wacom Intuos Pro S", 31496, 19685, 2047, 63,
+         INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x315 =
-       { "Wacom Intuos Pro M", WACOM_PKGLEN_INTUOS,  44704, 27940, 2047,
-         63, INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
-         .touch_max = 16 };
+       { "Wacom Intuos Pro M", 44704, 27940, 2047, 63,
+         INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x317 =
-       { "Wacom Intuos Pro L", WACOM_PKGLEN_INTUOS,  65024, 40640, 2047,
-         63, INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
-         .touch_max = 16 };
+       { "Wacom Intuos Pro L", 65024, 40640, 2047, 63,
+         INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0xF4 =
-       { "Wacom Cintiq 24HD",       WACOM_PKGLEN_INTUOS,   104280, 65400, 2047,
-         63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
+       { "Wacom Cintiq 24HD", 104280, 65400, 2047, 63,
+         WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
 static const struct wacom_features wacom_features_0xF8 =
-       { "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS,   104280, 65400, 2047, /* Pen */
-         63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
+       { "Wacom Cintiq 24HD touch", 104280, 65400, 2047, 63, /* Pen */
+         WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };
 static const struct wacom_features wacom_features_0xF6 =
        { "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */
-         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10 };
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x3F =
-       { "Wacom Cintiq 21UX",    WACOM_PKGLEN_INTUOS,    87200, 65600, 1023,
-         63, CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Cintiq 21UX", 87200, 65600, 1023, 63,
+         CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xC5 =
-       { "Wacom Cintiq 20WSX",   WACOM_PKGLEN_INTUOS,    86680, 54180, 1023,
-         63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Cintiq 20WSX", 86680, 54180, 1023, 63,
+         WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xC6 =
-       { "Wacom Cintiq 12WX",    WACOM_PKGLEN_INTUOS,    53020, 33440, 1023,
-         63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+       { "Wacom Cintiq 12WX", 53020, 33440, 1023, 63,
+         WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0x304 =
-       { "Wacom Cintiq 13HD",    WACOM_PKGLEN_INTUOS,    59352, 33648, 1023,
-         63, WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
+       { "Wacom Cintiq 13HD", 59352, 33648, 1023, 63,
+         WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
 static const struct wacom_features wacom_features_0xC7 =
-       { "Wacom DTU1931",        WACOM_PKGLEN_GRAPHIRE,  37832, 30305,  511,
-         0, PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom DTU1931", 37832, 30305, 511, 0,
+         PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xCE =
-       { "Wacom DTU2231",        WACOM_PKGLEN_GRAPHIRE,  47864, 27011,  511,
-         0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom DTU2231", 47864, 27011, 511, 0,
+         DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBMOUSE };
 static const struct wacom_features wacom_features_0xF0 =
-       { "Wacom DTU1631",        WACOM_PKGLEN_GRAPHIRE,  34623, 19553,  511,
-         0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom DTU1631", 34623, 19553, 511, 0,
+         DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xFB =
-       { "Wacom DTU1031",        WACOM_PKGLEN_DTUS,      22096, 13960,  511,
-         0, DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom DTU1031", 22096, 13960, 511, 0,
+         DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x57 =
-       { "Wacom DTK2241",        WACOM_PKGLEN_INTUOS,    95640, 54060, 2047,
-         63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
+       { "Wacom DTK2241", 95640, 54060, 2047, 63,
+         DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
 static const struct wacom_features wacom_features_0x59 = /* Pen */
-       { "Wacom DTH2242",        WACOM_PKGLEN_INTUOS,    95640, 54060, 2047,
-         63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
+       { "Wacom DTH2242", 95640, 54060, 2047, 63,
+         DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };
 static const struct wacom_features wacom_features_0x5D = /* Touch */
        { "Wacom DTH2242",       .type = WACOM_24HDT,
-         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10 };
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0xCC =
-       { "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    87000, 65400, 2047,
-         63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
+       { "Wacom Cintiq 21UX2", 87000, 65400, 2047, 63,
+         WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
 static const struct wacom_features wacom_features_0xFA =
-       { "Wacom Cintiq 22HD",    WACOM_PKGLEN_INTUOS,    95640, 54060, 2047,
-         63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
+       { "Wacom Cintiq 22HD", 95640, 54060, 2047, 63,
+         WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
 static const struct wacom_features wacom_features_0x5B =
-       { "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS,      95640, 54060, 2047,
-         63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
+       { "Wacom Cintiq 22HDT", 95640, 54060, 2047, 63,
+         WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e };
 static const struct wacom_features wacom_features_0x5E =
        { "Wacom Cintiq 22HDT", .type = WACOM_24HDT,
-         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5b, .touch_max = 10 };
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5b, .touch_max = 10,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x90 =
-       { "Wacom ISDv4 90",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
-         0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 90", 26202, 16325, 255, 0,
+         TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x93 =
-       { "Wacom ISDv4 93",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
-         0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 93", 26202, 16325, 255, 0,
+         TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x97 =
-       { "Wacom ISDv4 97",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  511,
-         0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 97", 26202, 16325, 511, 0,
+         TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x9A =
-       { "Wacom ISDv4 9A",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
-         0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 9A", 26202, 16325, 255, 0,
+         TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x9F =
-       { "Wacom ISDv4 9F",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
-         0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 9F", 26202, 16325, 255, 0,
+         TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xE2 =
-       { "Wacom ISDv4 E2",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,
-         0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 2 };
+       { "Wacom ISDv4 E2", 26202, 16325, 255, 0,
+         TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xE3 =
-       { "Wacom ISDv4 E3",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,
-         0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 2 };
+       { "Wacom ISDv4 E3", 26202, 16325, 255, 0,
+         TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xE5 =
-       { "Wacom ISDv4 E5",       WACOM_PKGLEN_MTOUCH,    26202, 16325,  255,
-         0, MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 E5", 26202, 16325, 255, 0,
+         MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xE6 =
-       { "Wacom ISDv4 E6",       WACOM_PKGLEN_TPC2FG,    27760, 15694,  255,
-         0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 2 };
+       { "Wacom ISDv4 E6", 27760, 15694, 255, 0,
+         TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xEC =
-       { "Wacom ISDv4 EC",       WACOM_PKGLEN_GRAPHIRE,  25710, 14500,  255,
-         0, TABLETPC,    WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 EC", 25710, 14500, 255, 0,
+         TABLETPC,    WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xED =
-       { "Wacom ISDv4 ED",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
-         0, TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 ED", 26202, 16325, 255, 0,
+         TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xEF =
-       { "Wacom ISDv4 EF",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
-         0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 EF", 26202, 16325, 255, 0,
+         TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x100 =
-       { "Wacom ISDv4 100",      WACOM_PKGLEN_MTTPC,     26202, 16325,  255,
-         0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 100", 26202, 16325, 255, 0,
+         MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x101 =
-       { "Wacom ISDv4 101",      WACOM_PKGLEN_MTTPC,     26202, 16325,  255,
-         0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 101", 26202, 16325, 255, 0,
+         MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x10D =
-       { "Wacom ISDv4 10D",      WACOM_PKGLEN_MTTPC,     26202, 16325,  255,
-         0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 10D", 26202, 16325, 255, 0,
+         MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x10E =
-       { "Wacom ISDv4 10E",      WACOM_PKGLEN_MTTPC,     27760, 15694,  255,
-         0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 10E", 27760, 15694, 255, 0,
+         MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x10F =
-       { "Wacom ISDv4 10F",      WACOM_PKGLEN_MTTPC,     27760, 15694,  255,
-         0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 10F", 27760, 15694, 255, 0,
+         MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x116 =
-       { "Wacom ISDv4 116",      WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
-         0, TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 116", 26202, 16325, 255, 0,
+         TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x12C =
+       { "Wacom ISDv4 12C", 27848, 15752, 2047, 0,
+         TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x4001 =
-       { "Wacom ISDv4 4001",      WACOM_PKGLEN_MTTPC,     26202, 16325,  255,
-         0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 4001", 26202, 16325, 255, 0,
+         MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x4004 =
-       { "Wacom ISDv4 4004",      WACOM_PKGLEN_MTTPC,     11060, 6220,  255,
-         0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 4004", 11060, 6220, 255, 0,
+         MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x5000 =
-       { "Wacom ISDv4 5000",      WACOM_PKGLEN_MTTPC,     27848, 15752,  1023,
-         0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 5000", 27848, 15752, 1023, 0,
+         MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x5002 =
-       { "Wacom ISDv4 5002",      WACOM_PKGLEN_MTTPC,     29576, 16724,  1023,
-         0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom ISDv4 5002", 29576, 16724, 1023, 0,
+         MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x47 =
-       { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023,
-         31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Intuos2 6x8", 20320, 16240, 1023, 31,
+         INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x84 =
-       { "Wacom Wireless Receiver", WACOM_PKGLEN_WIRELESS, 0, 0, 0,
-         0, WIRELESS, 0, 0, .touch_max = 16 };
+       { "Wacom Wireless Receiver", 0, 0, 0, 0,
+         WIRELESS, 0, 0, .touch_max = 16 };
 static const struct wacom_features wacom_features_0xD0 =
-       { "Wacom Bamboo 2FG",     WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 2 };
+       { "Wacom Bamboo 2FG", 14720, 9200, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD1 =
-       { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 2 };
+       { "Wacom Bamboo 2FG 4x5", 14720, 9200, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD2 =
-       { "Wacom Bamboo Craft",   WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 2 };
+       { "Wacom Bamboo Craft", 14720, 9200, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD3 =
-       { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN,     21648, 13700, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 2 };
+       { "Wacom Bamboo 2FG 6x8", 21648, 13700, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD4 =
-       { "Wacom Bamboo Pen",     WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Bamboo Pen", 14720, 9200, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xD5 =
-       { "Wacom Bamboo Pen 6x8",     WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Bamboo Pen 6x8", 21648, 13700, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xD6 =
-       { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN,   14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 2 };
+       { "Wacom BambooPT 2FG 4x5", 14720, 9200, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD7 =
-       { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 2 };
+       { "Wacom BambooPT 2FG Small", 14720, 9200, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD8 =
-       { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN,   21648, 13700, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 2 };
+       { "Wacom Bamboo Comic 2FG", 21648, 13700, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xDA =
-       { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN,  14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 2 };
+       { "Wacom Bamboo 2FG 4x5 SE", 14720, 9200, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xDB =
-       { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN,  21648, 13700, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 2 };
+       { "Wacom Bamboo 2FG 6x8 SE", 21648, 13700, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
 static const struct wacom_features wacom_features_0xDD =
-        { "Wacom Bamboo Connect", WACOM_PKGLEN_BBPEN,     14720,  9200, 1023,
-          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+        { "Wacom Bamboo Connect", 14720, 9200, 1023, 31,
+          BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xDE =
-        { "Wacom Bamboo 16FG 4x5", WACOM_PKGLEN_BBPEN,    14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 16 };
+        { "Wacom Bamboo 16FG 4x5", 14720, 9200, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 };
 static const struct wacom_features wacom_features_0xDF =
-        { "Wacom Bamboo 16FG 6x8", WACOM_PKGLEN_BBPEN,    21648, 13700, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 16 };
+        { "Wacom Bamboo 16FG 6x8", 21648, 13700, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 };
 static const struct wacom_features wacom_features_0x300 =
-       { "Wacom Bamboo One S",    WACOM_PKGLEN_BBPEN,    14720,  9225, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Bamboo One S", 14720, 9225, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x301 =
-       { "Wacom Bamboo One M",    WACOM_PKGLEN_BBPEN,    21648, 13530, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Bamboo One M", 21648, 13530, 1023, 31,
+         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x302 =
-       { "Wacom Intuos PT S",     WACOM_PKGLEN_BBPEN,    15200,  9500, 1023,
-         31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 16 };
+       { "Wacom Intuos PT S", 15200, 9500, 1023, 31,
+         INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x303 =
-       { "Wacom Intuos PT M",     WACOM_PKGLEN_BBPEN,    21600, 13500, 1023,
-         31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
-         .touch_max = 16 };
+       { "Wacom Intuos PT M", 21600, 13500, 1023, 31,
+         INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x30E =
-       { "Wacom Intuos S",        WACOM_PKGLEN_BBPEN,    15200,  9500, 1023,
-         31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+       { "Wacom Intuos S", 15200, 9500, 1023, 31,
+         INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x6004 =
-       { "ISD-V4",               WACOM_PKGLEN_GRAPHIRE,  12800,  8000,  255,
-         0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x0307 =
-       { "Wacom ISDv5 307", WACOM_PKGLEN_INTUOS,  59352,  33648, 2047,
-         63, CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
+       { "ISD-V4", 12800, 8000, 255, 0,
+         TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x307 =
+       { "Wacom ISDv5 307", 59352, 33648, 2047, 63,
+         CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 };
-static const struct wacom_features wacom_features_0x0309 =
+static const struct wacom_features wacom_features_0x309 =
        { "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */
-         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x0307, .touch_max = 10 };
+         .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x0307, .touch_max = 10,
+         .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 
-#define USB_DEVICE_WACOM(prod)                                 \
-       USB_DEVICE(USB_VENDOR_ID_WACOM, prod),                  \
-       .driver_info = (kernel_ulong_t)&wacom_features_##prod
+#define USB_DEVICE_WACOM(prod)                                         \
+       HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
+       .driver_data = (kernel_ulong_t)&wacom_features_##prod
 
-#define USB_DEVICE_DETAILED(prod, class, sub, proto)                   \
-       USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_WACOM, prod, class, \
-                                     sub, proto),                      \
-       .driver_info = (kernel_ulong_t)&wacom_features_##prod
+#define BT_DEVICE_WACOM(prod)                                          \
+       HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
+       .driver_data = (kernel_ulong_t)&wacom_features_##prod
 
 #define USB_DEVICE_LENOVO(prod)                                        \
-       USB_DEVICE(USB_VENDOR_ID_LENOVO, prod),                 \
-       .driver_info = (kernel_ulong_t)&wacom_features_##prod
+       HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, prod),                     \
+       .driver_data = (kernel_ulong_t)&wacom_features_##prod
 
-const struct usb_device_id wacom_ids[] = {
+const struct hid_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x00) },
+       { USB_DEVICE_WACOM(0x03) },
        { USB_DEVICE_WACOM(0x10) },
        { USB_DEVICE_WACOM(0x11) },
        { USB_DEVICE_WACOM(0x12) },
@@ -2372,20 +2613,16 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x17) },
        { USB_DEVICE_WACOM(0x18) },
        { USB_DEVICE_WACOM(0x19) },
-       { USB_DEVICE_WACOM(0x60) },
-       { USB_DEVICE_WACOM(0x61) },
-       { USB_DEVICE_WACOM(0x62) },
-       { USB_DEVICE_WACOM(0x63) },
-       { USB_DEVICE_WACOM(0x64) },
-       { USB_DEVICE_WACOM(0x65) },
-       { USB_DEVICE_WACOM(0x69) },
-       { USB_DEVICE_WACOM(0x6A) },
-       { USB_DEVICE_WACOM(0x6B) },
        { USB_DEVICE_WACOM(0x20) },
        { USB_DEVICE_WACOM(0x21) },
        { USB_DEVICE_WACOM(0x22) },
        { USB_DEVICE_WACOM(0x23) },
        { USB_DEVICE_WACOM(0x24) },
+       { USB_DEVICE_WACOM(0x26) },
+       { USB_DEVICE_WACOM(0x27) },
+       { USB_DEVICE_WACOM(0x28) },
+       { USB_DEVICE_WACOM(0x29) },
+       { USB_DEVICE_WACOM(0x2A) },
        { USB_DEVICE_WACOM(0x30) },
        { USB_DEVICE_WACOM(0x31) },
        { USB_DEVICE_WACOM(0x32) },
@@ -2395,20 +2632,34 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x37) },
        { USB_DEVICE_WACOM(0x38) },
        { USB_DEVICE_WACOM(0x39) },
-       { USB_DEVICE_WACOM(0xC4) },
-       { USB_DEVICE_WACOM(0xC0) },
-       { USB_DEVICE_WACOM(0xC2) },
-       { USB_DEVICE_WACOM(0x03) },
+       { USB_DEVICE_WACOM(0x3F) },
        { USB_DEVICE_WACOM(0x41) },
        { USB_DEVICE_WACOM(0x42) },
        { USB_DEVICE_WACOM(0x43) },
        { USB_DEVICE_WACOM(0x44) },
        { USB_DEVICE_WACOM(0x45) },
+       { USB_DEVICE_WACOM(0x47) },
        { USB_DEVICE_WACOM(0x57) },
        { USB_DEVICE_WACOM(0x59) },
-       { USB_DEVICE_DETAILED(0x5D, USB_CLASS_HID, 0, 0) },
        { USB_DEVICE_WACOM(0x5B) },
-       { USB_DEVICE_DETAILED(0x5E, USB_CLASS_HID, 0, 0) },
+       { USB_DEVICE_WACOM(0x5D) },
+       { USB_DEVICE_WACOM(0x5E) },
+       { USB_DEVICE_WACOM(0x60) },
+       { USB_DEVICE_WACOM(0x61) },
+       { USB_DEVICE_WACOM(0x62) },
+       { USB_DEVICE_WACOM(0x63) },
+       { USB_DEVICE_WACOM(0x64) },
+       { USB_DEVICE_WACOM(0x65) },
+       { USB_DEVICE_WACOM(0x69) },
+       { USB_DEVICE_WACOM(0x6A) },
+       { USB_DEVICE_WACOM(0x6B) },
+       { BT_DEVICE_WACOM(0x81) },
+       { USB_DEVICE_WACOM(0x84) },
+       { USB_DEVICE_WACOM(0x90) },
+       { USB_DEVICE_WACOM(0x93) },
+       { USB_DEVICE_WACOM(0x97) },
+       { USB_DEVICE_WACOM(0x9A) },
+       { USB_DEVICE_WACOM(0x9F) },
        { USB_DEVICE_WACOM(0xB0) },
        { USB_DEVICE_WACOM(0xB1) },
        { USB_DEVICE_WACOM(0xB2) },
@@ -2421,23 +2672,15 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xBA) },
        { USB_DEVICE_WACOM(0xBB) },
        { USB_DEVICE_WACOM(0xBC) },
-       { USB_DEVICE_WACOM(0x26) },
-       { USB_DEVICE_WACOM(0x27) },
-       { USB_DEVICE_WACOM(0x28) },
-       { USB_DEVICE_WACOM(0x29) },
-       { USB_DEVICE_WACOM(0x2A) },
-       { USB_DEVICE_WACOM(0x3F) },
+       { BT_DEVICE_WACOM(0xBD) },
+       { USB_DEVICE_WACOM(0xC0) },
+       { USB_DEVICE_WACOM(0xC2) },
+       { USB_DEVICE_WACOM(0xC4) },
        { USB_DEVICE_WACOM(0xC5) },
        { USB_DEVICE_WACOM(0xC6) },
        { USB_DEVICE_WACOM(0xC7) },
-       /*
-        * DTU-2231 has two interfaces on the same configuration,
-        * only one is used.
-        */
-       { USB_DEVICE_DETAILED(0xCE, USB_CLASS_HID,
-                             USB_INTERFACE_SUBCLASS_BOOT,
-                             USB_INTERFACE_PROTOCOL_MOUSE) },
-       { USB_DEVICE_WACOM(0x84) },
+       { USB_DEVICE_WACOM(0xCC) },
+       { USB_DEVICE_WACOM(0xCE) },
        { USB_DEVICE_WACOM(0xD0) },
        { USB_DEVICE_WACOM(0xD1) },
        { USB_DEVICE_WACOM(0xD2) },
@@ -2452,13 +2695,6 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xDD) },
        { USB_DEVICE_WACOM(0xDE) },
        { USB_DEVICE_WACOM(0xDF) },
-       { USB_DEVICE_WACOM(0xF0) },
-       { USB_DEVICE_WACOM(0xCC) },
-       { USB_DEVICE_WACOM(0x90) },
-       { USB_DEVICE_WACOM(0x93) },
-       { USB_DEVICE_WACOM(0x97) },
-       { USB_DEVICE_WACOM(0x9A) },
-       { USB_DEVICE_WACOM(0x9F) },
        { USB_DEVICE_WACOM(0xE2) },
        { USB_DEVICE_WACOM(0xE3) },
        { USB_DEVICE_WACOM(0xE5) },
@@ -2466,34 +2702,34 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xEC) },
        { USB_DEVICE_WACOM(0xED) },
        { USB_DEVICE_WACOM(0xEF) },
+       { USB_DEVICE_WACOM(0xF0) },
+       { USB_DEVICE_WACOM(0xF4) },
+       { USB_DEVICE_WACOM(0xF6) },
+       { USB_DEVICE_WACOM(0xF8) },
+       { USB_DEVICE_WACOM(0xFA) },
+       { USB_DEVICE_WACOM(0xFB) },
        { USB_DEVICE_WACOM(0x100) },
        { USB_DEVICE_WACOM(0x101) },
        { USB_DEVICE_WACOM(0x10D) },
        { USB_DEVICE_WACOM(0x10E) },
        { USB_DEVICE_WACOM(0x10F) },
        { USB_DEVICE_WACOM(0x116) },
+       { USB_DEVICE_WACOM(0x12C) },
        { USB_DEVICE_WACOM(0x300) },
        { USB_DEVICE_WACOM(0x301) },
-       { USB_DEVICE_DETAILED(0x302, USB_CLASS_HID, 0, 0) },
-       { USB_DEVICE_DETAILED(0x303, USB_CLASS_HID, 0, 0) },
-       { USB_DEVICE_DETAILED(0x30E, USB_CLASS_HID, 0, 0) },
+       { USB_DEVICE_WACOM(0x302) },
+       { USB_DEVICE_WACOM(0x303) },
        { USB_DEVICE_WACOM(0x304) },
-       { USB_DEVICE_DETAILED(0x314, USB_CLASS_HID, 0, 0) },
-       { USB_DEVICE_DETAILED(0x315, USB_CLASS_HID, 0, 0) },
-       { USB_DEVICE_DETAILED(0x317, USB_CLASS_HID, 0, 0) },
+       { USB_DEVICE_WACOM(0x307) },
+       { USB_DEVICE_WACOM(0x309) },
+       { USB_DEVICE_WACOM(0x30E) },
+       { USB_DEVICE_WACOM(0x314) },
+       { USB_DEVICE_WACOM(0x315) },
+       { USB_DEVICE_WACOM(0x317) },
        { USB_DEVICE_WACOM(0x4001) },
        { USB_DEVICE_WACOM(0x4004) },
        { USB_DEVICE_WACOM(0x5000) },
        { USB_DEVICE_WACOM(0x5002) },
-       { USB_DEVICE_WACOM(0x47) },
-       { USB_DEVICE_WACOM(0xF4) },
-       { USB_DEVICE_WACOM(0xF8) },
-       { USB_DEVICE_DETAILED(0xF6, USB_CLASS_HID, 0, 0) },
-       { USB_DEVICE_WACOM(0xFA) },
-       { USB_DEVICE_WACOM(0xFB) },
-       { USB_DEVICE_WACOM(0x0307) },
-       { USB_DEVICE_DETAILED(0x0309, USB_CLASS_HID, 0, 0) },
-       { USB_DEVICE_LENOVO(0x6004) },
        { }
 };
-MODULE_DEVICE_TABLE(usb, wacom_ids);
+MODULE_DEVICE_TABLE(hid, wacom_ids);
similarity index 88%
rename from drivers/input/tablet/wacom_wac.h
rename to drivers/hid/wacom_wac.h
index b2c9a9c1b5511ed23d03deac6ddcdd06a0e6bcbe..339ab5d81a2da3881f094318bf30bd0088687aa8 100644 (file)
@@ -46,6 +46,7 @@
 
 /* wacom data packet report IDs */
 #define WACOM_REPORT_PENABLED          2
+#define WACOM_REPORT_PENABLED_BT       3
 #define WACOM_REPORT_INTUOSREAD                5
 #define WACOM_REPORT_INTUOSWRITE       6
 #define WACOM_REPORT_INTUOSPAD         12
 #define WACOM_QUIRK_BBTOUCH_LOWRES     0x0002
 #define WACOM_QUIRK_NO_INPUT           0x0004
 #define WACOM_QUIRK_MONITOR            0x0008
+#define WACOM_QUIRK_BATTERY            0x0010
 
 enum {
        PENPARTNER = 0,
        GRAPHIRE,
+       GRAPHIRE_BT,
        WACOM_G4,
        PTU,
        PL,
@@ -83,6 +86,7 @@ enum {
        INTUOS3L,
        INTUOS4S,
        INTUOS4,
+       INTUOS4WL,
        INTUOS4L,
        INTUOS5S,
        INTUOS5,
@@ -114,7 +118,6 @@ enum {
 
 struct wacom_features {
        const char *name;
-       int pktlen;
        int x_max;
        int y_max;
        int pressure_max;
@@ -127,8 +130,8 @@ struct wacom_features {
        int device_type;
        int x_phy;
        int y_phy;
-       unsigned char unit;
-       unsigned char unitExpo;
+       unsigned unit;
+       int unitExpo;
        int x_fuzz;
        int y_fuzz;
        int pressure_fuzz;
@@ -137,6 +140,9 @@ struct wacom_features {
        unsigned touch_max;
        int oVid;
        int oPid;
+       int pktlen;
+       bool check_for_hid_type;
+       int hid_type;
 };
 
 struct wacom_shared {
@@ -150,16 +156,24 @@ struct wacom_shared {
 
 struct wacom_wac {
        char name[WACOM_NAME_MAX];
-       unsigned char *data;
+       char pad_name[WACOM_NAME_MAX];
+       char bat_name[WACOM_NAME_MAX];
+       char ac_name[WACOM_NAME_MAX];
+       unsigned char data[WACOM_PKGLEN_MAX];
        int tool[2];
        int id[2];
        __u32 serial[2];
        struct wacom_features features;
        struct wacom_shared *shared;
        struct input_dev *input;
+       struct input_dev *pad_input;
        int pid;
        int battery_capacity;
        int num_contacts_left;
+       int bat_charging;
+       int ps_connected;
+       u8 bt_features;
+       u8 bt_high_speed;
 };
 
 #endif
index a5121b09c63f5f44180dfb9c1e7de575cc1b35d0..623bb9e0d5a41a291aeca39c6bc712bdf8d6c962 100644 (file)
@@ -73,22 +73,6 @@ config TABLET_USB_KBTAB
          To compile this driver as a module, choose M here: the
          module will be called kbtab.
 
-config TABLET_USB_WACOM
-       tristate "Wacom Intuos/Graphire tablet support (USB)"
-       depends on USB_ARCH_HAS_HCD
-       select POWER_SUPPLY
-       select USB
-       select NEW_LEDS
-       select LEDS_CLASS
-       help
-         Say Y here if you want to use the USB version of the Wacom Intuos
-         or Graphire tablet.  Make sure to say Y to "Mouse support"
-         (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-         (CONFIG_INPUT_EVDEV) as well.
-
-         To compile this driver as a module, choose M here: the
-         module will be called wacom.
-
 config TABLET_SERIAL_WACOM4
        tristate "Wacom protocol 4 serial tablet support"
        select SERIO
index 4d9339fb3b6361f10d00f6f72153412ddd83316c..2e130101cf3c8c800634a8b486b9cf5b7362fb4a 100644 (file)
@@ -2,13 +2,10 @@
 # Makefile for the tablet drivers
 #
 
-# Multipart objects.
-wacom-objs     := wacom_wac.o wacom_sys.o
 
 obj-$(CONFIG_TABLET_USB_ACECAD)        += acecad.o
 obj-$(CONFIG_TABLET_USB_AIPTEK)        += aiptek.o
 obj-$(CONFIG_TABLET_USB_GTCO)  += gtco.o
 obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o
 obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o
-obj-$(CONFIG_TABLET_USB_WACOM) += wacom.o
 obj-$(CONFIG_TABLET_SERIAL_WACOM4) += wacom_serial4.o
index 77632cf159c0d13ba5877a0d5b717b091ce83b4b..07fa80671db0170e4d6658bb5d0386ab6567899a 100644 (file)
@@ -310,6 +310,11 @@ struct hid_item {
  */
 #define HID_GROUP_RMI                          0x0100
 
+/*
+ * Vendor specific HID device groups
+ */
+#define HID_GROUP_WACOM                                0x0101
+
 /*
  * This is the global environment of the parser. This information is
  * persistent for main-items. The global environment can be saved and