lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1405449946-11515-24-git-send-email-benjamin.tissoires@redhat.com>
Date:	Tue, 15 Jul 2014 14:45:46 -0400
From:	Benjamin Tissoires <benjamin.tissoires@...hat.com>
To:	Dmitry Torokhov <dmitry.torokhov@...il.com>,
	Jiri Kosina <jkosina@...e.cz>,
	Ping Cheng <pinglinux@...il.com>,
	Jason Gerecke <killertofu@...il.com>
Cc:	linux-kernel@...r.kernel.org, linux-input@...r.kernel.org
Subject: [PATCH v2 23/23] Input - wacom: Move the USB (now hid) Wacom driver in drivers/hid

wacom.ko is now a full HID driver, we have to move it into the proper
subdirectory: drivers/hid.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@...hat.com>
---

new in v2

 drivers/hid/Kconfig              |   13 +
 drivers/hid/Makefile             |    3 +
 drivers/hid/wacom.h              |  138 +++
 drivers/hid/wacom_sys.c          | 1257 +++++++++++++++++++
 drivers/hid/wacom_wac.c          | 2534 ++++++++++++++++++++++++++++++++++++++
 drivers/hid/wacom_wac.h          |  169 +++
 drivers/input/tablet/Kconfig     |   16 -
 drivers/input/tablet/Makefile    |    3 -
 drivers/input/tablet/wacom.h     |  138 ---
 drivers/input/tablet/wacom_sys.c | 1257 -------------------
 drivers/input/tablet/wacom_wac.c | 2534 --------------------------------------
 drivers/input/tablet/wacom_wac.h |  169 ---
 12 files changed, 4114 insertions(+), 4117 deletions(-)
 create mode 100644 drivers/hid/wacom.h
 create mode 100644 drivers/hid/wacom_sys.c
 create mode 100644 drivers/hid/wacom_wac.c
 create mode 100644 drivers/hid/wacom_wac.h
 delete mode 100644 drivers/input/tablet/wacom.h
 delete mode 100644 drivers/input/tablet/wacom_sys.c
 delete mode 100644 drivers/input/tablet/wacom_wac.c
 delete mode 100644 drivers/input/tablet/wacom_wac.h

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 7af9d0b..5a7517b 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -744,6 +744,19 @@ config HID_WACOM
 	---help---
 	Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.
 
+config HID_USB_WACOM
+	tristate "Wacom Intuos/Graphire tablet support (USB)"
+	depends on HID
+	select POWER_SUPPLY
+	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.
+
+	  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"
 	depends on HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index fc712dd..a9e9f48 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -115,6 +115,9 @@ 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_USB_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
diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h
new file mode 100644
index 0000000..dd67b7d
--- /dev/null
+++ b/drivers/hid/wacom.h
@@ -0,0 +1,138 @@
+/*
+ * drivers/input/tablet/wacom.h
+ *
+ *  USB Wacom tablet support
+ *
+ *  Copyright (c) 2000-2004 Vojtech Pavlik	<vojtech@....cz>
+ *  Copyright (c) 2000 Andreas Bach Aaen	<abach@...fanet.dk>
+ *  Copyright (c) 2000 Clifford Wolf		<clifford@...fford.at>
+ *  Copyright (c) 2000 Sam Mosel		<sam.mosel@...puter.org>
+ *  Copyright (c) 2000 James E. Blair		<corvus@....org>
+ *  Copyright (c) 2000 Daniel Egger		<egger@...e.de>
+ *  Copyright (c) 2001 Frederic Lepied		<flepied@...drakesoft.com>
+ *  Copyright (c) 2004 Panagiotis Issaris	<panagiotis.issaris@...h.kuleuven.ac.be>
+ *  Copyright (c) 2002-2011 Ping Cheng		<pingc@...om.com>
+ *
+ *  ChangeLog:
+ *      v0.1 (vp)  - Initial release
+ *      v0.2 (aba) - Support for all buttons / combinations
+ *      v0.3 (vp)  - Support for Intuos added
+ *	v0.4 (sm)  - Support for more Intuos models, menustrip
+ *			relative mode, proximity.
+ *	v0.5 (vp)  - Big cleanup, nifty features removed,
+ *			they belong in userspace
+ *	v1.8 (vp)  - Submit URB only when operating, moved to CVS,
+ *			use input_report_key instead of report_btn and
+ *			other cleanups
+ *	v1.11 (vp) - Add URB ->dev setting for new kernels
+ *	v1.11 (jb) - Add support for the 4D Mouse & Lens
+ *	v1.12 (de) - Add support for two more inking pen IDs
+ *	v1.14 (vp) - Use new USB device id probing scheme.
+ *		     Fix Wacom Graphire mouse wheel
+ *	v1.18 (vp) - Fix mouse wheel direction
+ *		     Make mouse relative
+ *      v1.20 (fl) - Report tool id for Intuos devices
+ *                 - Multi tools support
+ *                 - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...)
+ *                 - Add PL models support
+ *		   - Fix Wacom Graphire mouse wheel again
+ *	v1.21 (vp) - Removed protocol descriptions
+ *		   - Added MISC_SERIAL for tool serial numbers
+ *	      (gb) - Identify version on module load.
+ *    v1.21.1 (fl) - added Graphire2 support
+ *    v1.21.2 (fl) - added Intuos2 support
+ *                 - added all the PL ids
+ *    v1.21.3 (fl) - added another eraser id from Neil Okamoto
+ *                 - added smooth filter for Graphire from Peri Hankey
+ *                 - added PenPartner support from Olaf van Es
+ *                 - new tool ids from Ole Martin Bjoerndalen
+ *	v1.29 (pc) - Add support for more tablets
+ *		   - Fix pressure reporting
+ *	v1.30 (vp) - Merge 2.4 and 2.5 drivers
+ *		   - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
+ *		   - Cleanups here and there
+ *    v1.30.1 (pi) - Added Graphire3 support
+ *	v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
+ *	v1.43 (pc) - Added support for Cintiq 21UX
+ *		   - Fixed a Graphire bug
+ *		   - Merged wacom_intuos3_irq into wacom_intuos_irq
+ *	v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc.
+ *		   - Report Device IDs
+ *      v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19
+ *                 - Minor data report fix
+ *      v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c,
+ *		   - where wacom_sys.c deals with system specific code,
+ *		   - and wacom_wac.c deals with Wacom specific code
+ *		   - Support Intuos3 4x6
+ *      v1.47 (pc) - Added support for Bamboo
+ *      v1.48 (pc) - Added support for Bamboo1, BambooFun, and Cintiq 12WX
+ *      v1.49 (pc) - Added support for USB Tablet PC (0x90, 0x93, and 0x9A)
+ *      v1.50 (pc) - Fixed a TabletPC touch bug in 2.6.28
+ *      v1.51 (pc) - Added support for Intuos4
+ *      v1.52 (pc) - Query Wacom data upon system resume
+ *                 - add defines for features->type
+ *                 - add new devices (0x9F, 0xE2, and 0XE3)
+ */
+
+/*
+ * 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.
+ */
+#ifndef WACOM_H
+#define WACOM_H
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/usb/input.h>
+#include <linux/power_supply.h>
+#include <asm/unaligned.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.53"
+#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@....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 {
+	struct usb_device *usbdev;
+	struct usb_interface *intf;
+	struct wacom_wac wacom_wac;
+	struct hid_device *hdev;
+	struct mutex lock;
+	struct work_struct work;
+	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;
+	struct power_supply battery;
+};
+
+static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
+{
+	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+	schedule_work(&wacom->work);
+}
+
+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
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
new file mode 100644
index 0000000..9dbb6dd
--- /dev/null
+++ b/drivers/hid/wacom_sys.c
@@ -0,0 +1,1257 @@
+/*
+ * drivers/input/tablet/wacom_sys.c
+ *
+ *  USB Wacom tablet support - system specific code
+ */
+
+/*
+ * 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.
+ */
+
+#include "wacom_wac.h"
+#include "wacom.h"
+#include <linux/hid.h>
+
+#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_RETRIES		10
+
+static int wacom_get_report(struct hid_device *hdev, u8 type, u8 id,
+			    void *buf, size_t size, unsigned int retries)
+{
+	int retval;
+
+	do {
+		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 hid_device *hdev, u8 type, u8 id,
+			    void *buf, size_t size, unsigned int retries)
+{
+	int retval;
+
+	do {
+		retval = hid_hw_raw_request(hdev, id, buf, size, type,
+				HID_REQ_SET_REPORT);
+	} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
+
+	return retval;
+}
+
+static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
+		u8 *raw_data, int size)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+
+	if (size > WACOM_PKGLEN_MAX)
+		return 1;
+
+	memcpy(wacom->wacom_wac.data, raw_data, size);
+
+	wacom_wac_irq(&wacom->wacom_wac, size);
+
+	return 0;
+}
+
+static int wacom_open(struct input_dev *dev)
+{
+	struct wacom *wacom = input_get_drvdata(dev);
+	int retval;
+
+	mutex_lock(&wacom->lock);
+	retval = hid_hw_open(wacom->hdev);
+	mutex_unlock(&wacom->lock);
+
+	return retval;
+}
+
+static void wacom_close(struct input_dev *dev)
+{
+	struct wacom *wacom = input_get_drvdata(dev);
+
+	mutex_lock(&wacom->lock);
+	hid_hw_close(wacom->hdev);
+	mutex_unlock(&wacom->lock);
+}
+
+/*
+ * 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 unit, int exponent)
+{
+	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_feature_mapping(struct hid_device *hdev,
+		struct hid_field *field, struct hid_usage *usage)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	struct wacom_features *features = &wacom->wacom_wac.features;
+
+	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;
+	}
+}
+
+/*
+ * Interface Descriptor of wacom devices can be incomplete and
+ * inconsistent so wacom_features table is used to store stylus
+ * device's packet lengths, various maximum values, and tablet
+ * resolution based on product ID's.
+ *
+ * For devices that contain 2 interfaces, wacom_features table is
+ * inaccurate for the touch interface.  Since the Interface Descriptor
+ * for touch interfaces has pretty complete data, this function exists
+ * to query tablet for this missing information instead of hard coding in
+ * an additional table.
+ *
+ * A typical Interface Descriptor for a stylus will contain a
+ * boot mouse application collection that is not of interest and this
+ * function will ignore it.
+ *
+ * It also contains a digitizer application collection that also is not
+ * of interest since any information it contains would be duplicate
+ * of what is in wacom_features. Usually it defines a report of an array
+ * of bytes that could be used as max length of the stylus packet returned.
+ * If it happens to define a Digitizer-Stylus Physical Collection then
+ * the X and Y logical values contain valid data but it is ignored.
+ *
+ * A typical Interface Descriptor for a touch interface will contain a
+ * Digitizer-Finger Physical Collection which will define both logical
+ * X/Y maximum as well as the physical size of tablet. Since touch
+ * interfaces haven't supported pressure or distance, this is enough
+ * information to override invalid values in the wacom_features table.
+ *
+ * Intuos5 touch interface and 3rd gen Bamboo Touch do not contain useful
+ * data. We deal with them after returning from this function.
+ */
+static void wacom_usage_mapping(struct hid_device *hdev,
+		struct hid_field *field, struct hid_usage *usage)
+{
+	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.
+	*/
+	if (!pen && !finger)
+		return;
+
+	if (finger && !features->touch_max)
+		/* touch device at least supports one touch point */
+		features->touch_max = 1;
+
+	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;
+			}
+		} 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;
+	}
+}
+
+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);
+			}
+		}
+	}
+
+	/* 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 hid_device *hdev, int report_id,
+		int length, int mode)
+{
+	unsigned char *rep_data;
+	int error = -ENOMEM, limit = 0;
+
+	rep_data = kzalloc(length, GFP_KERNEL);
+	if (!rep_data)
+		return error;
+
+	do {
+		rep_data[0] = report_id;
+		rep_data[1] = mode;
+
+		error = wacom_set_report(hdev, HID_FEATURE_REPORT,
+		                         report_id, 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);
+
+	return error < 0 ? error : 0;
+}
+
+/*
+ * Switch the tablet into its most-capable mode. Wacom tablets are
+ * typically configured to power-up in a mode which sends mouse-like
+ * reports to the OS. To get absolute position, pressure data, etc.
+ * from the tablet, it is necessary to switch the tablet out of this
+ * mode and into one which sends the full range of tablet data.
+ */
+static int wacom_query_tablet_data(struct hid_device *hdev,
+		struct wacom_features *features)
+{
+	if (features->device_type == BTN_TOOL_FINGER) {
+		if (features->type > TABLETPC) {
+			/* MT Tablet PC touch */
+			return wacom_set_device_mode(hdev, 3, 4, 4);
+		}
+		else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) {
+			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(hdev, 2, 2, 2);
+		}
+	}
+
+	return 0;
+}
+
+static void wacom_retrieve_hid_descriptor(struct hid_device *hdev,
+					 struct wacom_features *features)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	struct usb_interface *intf = wacom->intf;
+
+	/* default features */
+	features->device_type = BTN_TOOL_PEN;
+	features->x_fuzz = 4;
+	features->y_fuzz = 4;
+	features->pressure_fuzz = 0;
+	features->distance_fuzz = 0;
+
+	/*
+	 * The wireless device HID is basic and layout conflicts with
+	 * other tablets (monitor and touch interface can look like pen).
+	 * Skip the query for this type and modify defaults based on
+	 * interface number.
+	 */
+	if (features->type == WIRELESS) {
+		if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
+			features->device_type = 0;
+		} else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) {
+			features->device_type = BTN_TOOL_FINGER;
+			features->pktlen = WACOM_PKGLEN_BBTOUCH3;
+		}
+	}
+
+	/* only devices that support touch need to retrieve the info */
+	if (features->type < BAMBOO_PT)
+		return;
+
+	wacom_parse_hid(hdev, features);
+}
+
+struct wacom_hdev_data {
+	struct list_head list;
+	struct kref kref;
+	struct hid_device *dev;
+	struct wacom_shared shared;
+};
+
+static LIST_HEAD(wacom_udev_list);
+static DEFINE_MUTEX(wacom_udev_list_lock);
+
+static bool wacom_are_sibling(struct hid_device *hdev,
+		struct hid_device *sibling)
+{
+	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 (vid == 0 && pid == 0) {
+		vid = hdev->vendor;
+		pid = hdev->product;
+	}
+
+	if (vid != sibling->vendor || pid != sibling->product)
+		return false;
+
+	/* 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 !strncmp(hdev->phys, sibling->phys, n1);
+}
+
+static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
+{
+	struct wacom_hdev_data *data;
+
+	list_for_each_entry(data, &wacom_udev_list, list) {
+		if (wacom_are_sibling(hdev, data->dev)) {
+			kref_get(&data->kref);
+			return data;
+		}
+	}
+
+	return NULL;
+}
+
+static int wacom_add_shared_data(struct hid_device *hdev)
+{
+	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_hdev_data(hdev);
+	if (!data) {
+		data = kzalloc(sizeof(struct wacom_hdev_data), GFP_KERNEL);
+		if (!data) {
+			retval = -ENOMEM;
+			goto out;
+		}
+
+		kref_init(&data->kref);
+		data->dev = hdev;
+		list_add_tail(&data->list, &wacom_udev_list);
+	}
+
+	wacom_wac->shared = &data->shared;
+
+out:
+	mutex_unlock(&wacom_udev_list_lock);
+	return retval;
+}
+
+static void wacom_release_shared_data(struct kref *kref)
+{
+	struct wacom_hdev_data *data =
+		container_of(kref, struct wacom_hdev_data, kref);
+
+	mutex_lock(&wacom_udev_list_lock);
+	list_del(&data->list);
+	mutex_unlock(&wacom_udev_list_lock);
+
+	kfree(data);
+}
+
+static void wacom_remove_shared_data(struct wacom_wac *wacom)
+{
+	struct wacom_hdev_data *data;
+
+	if (wacom->shared) {
+		data = container_of(wacom->shared, struct wacom_hdev_data, shared);
+		kref_put(&data->kref, wacom_release_shared_data);
+		wacom->shared = NULL;
+	}
+}
+
+static int wacom_led_control(struct wacom *wacom)
+{
+	unsigned char *buf;
+	int retval;
+
+	buf = kzalloc(9, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (wacom->wacom_wac.features.type >= INTUOS5S &&
+	    wacom->wacom_wac.features.type <= INTUOSPL) {
+		/*
+		 * Touch Ring and crop mark LED luminance may take on
+		 * one of four values:
+		 *    0 = Low; 1 = Medium; 2 = High; 3 = Off
+		 */
+		int ring_led = wacom->led.select[0] & 0x03;
+		int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03;
+		int crop_lum = 0;
+
+		buf[0] = WAC_CMD_LED_CONTROL;
+		buf[1] = (crop_lum << 4) | (ring_lum << 2) | (ring_led);
+	}
+	else {
+		int led = wacom->led.select[0] | 0x4;
+
+		if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
+		    wacom->wacom_wac.features.type == WACOM_24HD)
+			led |= (wacom->led.select[1] << 4) | 0x40;
+
+		buf[0] = WAC_CMD_LED_CONTROL;
+		buf[1] = led;
+		buf[2] = wacom->led.llv;
+		buf[3] = wacom->led.hlv;
+		buf[4] = wacom->led.img_lum;
+	}
+
+	retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
+				  WAC_CMD_LED_CONTROL, buf, 9, WAC_CMD_RETRIES);
+	kfree(buf);
+
+	return retval;
+}
+
+static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img)
+{
+	unsigned char *buf;
+	int i, retval;
+
+	buf = kzalloc(259, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/* Send 'start' command */
+	buf[0] = WAC_CMD_ICON_START;
+	buf[1] = 1;
+	retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
+				  WAC_CMD_ICON_START, buf, 2, WAC_CMD_RETRIES);
+	if (retval < 0)
+		goto out;
+
+	buf[0] = WAC_CMD_ICON_XFER;
+	buf[1] = button_id & 0x07;
+	for (i = 0; i < 4; i++) {
+		buf[2] = i;
+		memcpy(buf + 3, img + i * 256, 256);
+
+		retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
+					  WAC_CMD_ICON_XFER,
+					  buf, 259, WAC_CMD_RETRIES);
+		if (retval < 0)
+			break;
+	}
+
+	/* Send 'stop' */
+	buf[0] = WAC_CMD_ICON_START;
+	buf[1] = 0;
+	wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, WAC_CMD_ICON_START,
+			 buf, 2, WAC_CMD_RETRIES);
+
+out:
+	kfree(buf);
+	return retval;
+}
+
+static ssize_t wacom_led_select_store(struct device *dev, int set_id,
+				      const char *buf, size_t count)
+{
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	unsigned int id;
+	int err;
+
+	err = kstrtouint(buf, 10, &id);
+	if (err)
+		return err;
+
+	mutex_lock(&wacom->lock);
+
+	wacom->led.select[set_id] = id & 0x3;
+	err = wacom_led_control(wacom);
+
+	mutex_unlock(&wacom->lock);
+
+	return err < 0 ? err : count;
+}
+
+#define DEVICE_LED_SELECT_ATTR(SET_ID)					\
+static ssize_t wacom_led##SET_ID##_select_store(struct device *dev,	\
+	struct device_attribute *attr, const char *buf, size_t count)	\
+{									\
+	return wacom_led_select_store(dev, SET_ID, buf, count);		\
+}									\
+static ssize_t wacom_led##SET_ID##_select_show(struct device *dev,	\
+	struct device_attribute *attr, char *buf)			\
+{									\
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
+	struct 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,	\
+		    wacom_led##SET_ID##_select_show,			\
+		    wacom_led##SET_ID##_select_store)
+
+DEVICE_LED_SELECT_ATTR(0);
+DEVICE_LED_SELECT_ATTR(1);
+
+static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
+				     const char *buf, size_t count)
+{
+	unsigned int value;
+	int err;
+
+	err = kstrtouint(buf, 10, &value);
+	if (err)
+		return err;
+
+	mutex_lock(&wacom->lock);
+
+	*dest = value & 0x7f;
+	err = wacom_led_control(wacom);
+
+	mutex_unlock(&wacom->lock);
+
+	return err < 0 ? err : count;
+}
+
+#define DEVICE_LUMINANCE_ATTR(name, field)				\
+static ssize_t wacom_##name##_luminance_store(struct device *dev,	\
+	struct device_attribute *attr, const char *buf, size_t count)	\
+{									\
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
+	struct wacom *wacom = hid_get_drvdata(hdev);			\
+									\
+	return wacom_luminance_store(wacom, &wacom->led.field,		\
+				     buf, count);			\
+}									\
+static DEVICE_ATTR(name##_luminance, S_IWUSR,				\
+		   NULL, wacom_##name##_luminance_store)
+
+DEVICE_LUMINANCE_ATTR(status0, llv);
+DEVICE_LUMINANCE_ATTR(status1, hlv);
+DEVICE_LUMINANCE_ATTR(buttons, img_lum);
+
+static ssize_t wacom_button_image_store(struct device *dev, int button_id,
+					const char *buf, size_t count)
+{
+	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	int err;
+
+	if (count != 1024)
+		return -EINVAL;
+
+	mutex_lock(&wacom->lock);
+
+	err = wacom_led_putimage(wacom, button_id, buf);
+
+	mutex_unlock(&wacom->lock);
+
+	return err < 0 ? err : count;
+}
+
+#define DEVICE_BTNIMG_ATTR(BUTTON_ID)					\
+static ssize_t wacom_btnimg##BUTTON_ID##_store(struct device *dev,	\
+	struct device_attribute *attr, const char *buf, size_t count)	\
+{									\
+	return wacom_button_image_store(dev, BUTTON_ID, buf, count);	\
+}									\
+static DEVICE_ATTR(button##BUTTON_ID##_rawimg, S_IWUSR,			\
+		   NULL, wacom_btnimg##BUTTON_ID##_store)
+
+DEVICE_BTNIMG_ATTR(0);
+DEVICE_BTNIMG_ATTR(1);
+DEVICE_BTNIMG_ATTR(2);
+DEVICE_BTNIMG_ATTR(3);
+DEVICE_BTNIMG_ATTR(4);
+DEVICE_BTNIMG_ATTR(5);
+DEVICE_BTNIMG_ATTR(6);
+DEVICE_BTNIMG_ATTR(7);
+
+static struct attribute *cintiq_led_attrs[] = {
+	&dev_attr_status_led0_select.attr,
+	&dev_attr_status_led1_select.attr,
+	NULL
+};
+
+static struct attribute_group cintiq_led_attr_group = {
+	.name = "wacom_led",
+	.attrs = cintiq_led_attrs,
+};
+
+static struct attribute *intuos4_led_attrs[] = {
+	&dev_attr_status0_luminance.attr,
+	&dev_attr_status1_luminance.attr,
+	&dev_attr_status_led0_select.attr,
+	&dev_attr_buttons_luminance.attr,
+	&dev_attr_button0_rawimg.attr,
+	&dev_attr_button1_rawimg.attr,
+	&dev_attr_button2_rawimg.attr,
+	&dev_attr_button3_rawimg.attr,
+	&dev_attr_button4_rawimg.attr,
+	&dev_attr_button5_rawimg.attr,
+	&dev_attr_button6_rawimg.attr,
+	&dev_attr_button7_rawimg.attr,
+	NULL
+};
+
+static struct attribute_group intuos4_led_attr_group = {
+	.name = "wacom_led",
+	.attrs = intuos4_led_attrs,
+};
+
+static struct attribute *intuos5_led_attrs[] = {
+	&dev_attr_status0_luminance.attr,
+	&dev_attr_status_led0_select.attr,
+	NULL
+};
+
+static struct attribute_group intuos5_led_attr_group = {
+	.name = "wacom_led",
+	.attrs = intuos5_led_attrs,
+};
+
+static int wacom_initialize_leds(struct wacom *wacom)
+{
+	int error;
+
+	/* Initialize default values */
+	switch (wacom->wacom_wac.features.type) {
+	case INTUOS4S:
+	case INTUOS4:
+	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->hdev->dev.kobj,
+					   &intuos4_led_attr_group);
+		break;
+
+	case WACOM_24HD:
+	case WACOM_21UX2:
+		wacom->led.select[0] = 0;
+		wacom->led.select[1] = 0;
+		wacom->led.llv = 0;
+		wacom->led.hlv = 0;
+		wacom->led.img_lum = 0;
+
+		error = sysfs_create_group(&wacom->hdev->dev.kobj,
+					   &cintiq_led_attr_group);
+		break;
+
+	case INTUOS5S:
+	case INTUOS5:
+	case INTUOS5L:
+	case INTUOSPS:
+	case INTUOSPM:
+	case INTUOSPL:
+		if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN) {
+			wacom->led.select[0] = 0;
+			wacom->led.select[1] = 0;
+			wacom->led.llv = 32;
+			wacom->led.hlv = 0;
+			wacom->led.img_lum = 0;
+
+			error = sysfs_create_group(&wacom->hdev->dev.kobj,
+						  &intuos5_led_attr_group);
+		} else
+			return 0;
+		break;
+
+	default:
+		return 0;
+	}
+
+	if (error) {
+		hid_err(wacom->hdev,
+			"cannot create sysfs group err: %d\n", error);
+		return error;
+	}
+	wacom_led_control(wacom);
+
+	return 0;
+}
+
+static void wacom_destroy_leds(struct wacom *wacom)
+{
+	switch (wacom->wacom_wac.features.type) {
+	case INTUOS4S:
+	case INTUOS4:
+	case INTUOS4L:
+		sysfs_remove_group(&wacom->hdev->dev.kobj,
+				   &intuos4_led_attr_group);
+		break;
+
+	case WACOM_24HD:
+	case WACOM_21UX2:
+		sysfs_remove_group(&wacom->hdev->dev.kobj,
+				   &cintiq_led_attr_group);
+		break;
+
+	case INTUOS5S:
+	case INTUOS5:
+	case INTUOS5L:
+	case INTUOSPS:
+	case INTUOSPM:
+	case INTUOSPL:
+		if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN)
+			sysfs_remove_group(&wacom->hdev->dev.kobj,
+					   &intuos5_led_attr_group);
+		break;
+	}
+}
+
+static enum power_supply_property wacom_battery_props[] = {
+	POWER_SUPPLY_PROP_SCOPE,
+	POWER_SUPPLY_PROP_CAPACITY
+};
+
+static int wacom_battery_get_property(struct power_supply *psy,
+				      enum power_supply_property psp,
+				      union power_supply_propval *val)
+{
+	struct wacom *wacom = container_of(psy, struct wacom, battery);
+	int ret = 0;
+
+	switch (psp) {
+		case POWER_SUPPLY_PROP_SCOPE:
+			val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+			break;
+		case POWER_SUPPLY_PROP_CAPACITY:
+			val->intval =
+				wacom->wacom_wac.battery_capacity * 100 / 31;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+	}
+
+	return ret;
+}
+
+static int wacom_initialize_battery(struct wacom *wacom)
+{
+	int error = 0;
+
+	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";
+		wacom->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+		wacom->battery.use_for_apm = 0;
+
+		error = power_supply_register(&wacom->hdev->dev,
+					      &wacom->battery);
+
+		if (!error)
+			power_supply_powers(&wacom->battery,
+					    &wacom->hdev->dev);
+	}
+
+	return error;
+}
+
+static void wacom_destroy_battery(struct wacom *wacom)
+{
+	if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR &&
+	    wacom->battery.dev) {
+		power_supply_unregister(&wacom->battery);
+		wacom->battery.dev = NULL;
+	}
+}
+
+static struct input_dev *wacom_allocate_input(struct wacom *wacom)
+{
+	struct input_dev *input_dev;
+	struct hid_device *hdev = wacom->hdev;
+	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return NULL;
+
+	input_dev->name = wacom_wac->name;
+	input_dev->phys = hdev->phys;
+	input_dev->dev.parent = &hdev->dev;
+	input_dev->open = wacom_open;
+	input_dev->close = wacom_close;
+	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 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:
+	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;
+}
+
+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;
+
+	/*
+	 * Regardless if this is a disconnect or a new tablet,
+	 * remove any existing input and battery devices.
+	 */
+
+	wacom_destroy_battery(wacom);
+
+	/* Stylus interface */
+	hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
+	wacom1 = hid_get_drvdata(hdev1);
+	wacom_wac1 = &(wacom1->wacom_wac);
+	wacom_unregister_inputs(wacom1);
+
+	/* Touch interface */
+	hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
+	wacom2 = hid_get_drvdata(hdev2);
+	wacom_wac2 = &(wacom2->wacom_wac);
+	wacom_unregister_inputs(wacom2);
+
+	if (wacom_wac->pid == 0) {
+		hid_info(wacom->hdev, "wireless tablet disconnected\n");
+	} else {
+		const struct hid_device_id *id = wacom_ids;
+
+		hid_info(wacom->hdev, "wireless tablet connected with PID %x\n",
+			 wacom_wac->pid);
+
+		while (id->bus) {
+			if (id->vendor == USB_VENDOR_ID_WACOM &&
+			    id->product == wacom_wac->pid)
+				break;
+			id++;
+		}
+
+		if (!id->bus) {
+			hid_info(wacom->hdev, "ignoring unknown PID.\n");
+			return;
+		}
+
+		/* Stylus interface */
+		wacom_wac1->features =
+			*((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_inputs(wacom1);
+		if (error)
+			goto fail;
+
+		/* Touch interface */
+		if (wacom_wac1->features.touch_max ||
+		    wacom_wac1->features.type == INTUOSHT) {
+			wacom_wac2->features =
+				*((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;
+			if (wacom_wac2->features.touch_max)
+				snprintf(wacom_wac2->name, WACOM_NAME_MAX,
+					 "%s (WL) Finger",wacom_wac2->features.name);
+			else
+				snprintf(wacom_wac2->name, WACOM_NAME_MAX,
+					 "%s (WL) Pad",wacom_wac2->features.name);
+			snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
+				 "%s (WL) Pad", wacom_wac2->features.name);
+			error = wacom_register_inputs(wacom2);
+			if (error)
+				goto fail;
+
+			if (wacom_wac1->features.type == INTUOSHT &&
+			    wacom_wac1->features.touch_max)
+				wacom_wac->shared->touch_input = wacom_wac2->input;
+		}
+
+		error = wacom_initialize_battery(wacom);
+		if (error)
+			goto fail;
+	}
+
+	return;
+
+fail:
+	wacom_unregister_inputs(wacom1);
+	wacom_unregister_inputs(wacom2);
+	return;
+}
+
+/*
+ * Not all devices report physical dimensions from HID.
+ * Compute the default from hardcoded logical dimension
+ * and resolution before driver overwrites them.
+ */
+static void wacom_set_default_phy(struct wacom_features *features)
+{
+	if (features->x_resolution) {
+		features->x_phy = (features->x_max * 100) /
+					features->x_resolution;
+		features->y_phy = (features->y_max * 100) /
+					features->y_resolution;
+	}
+}
+
+static void wacom_calculate_res(struct wacom_features *features)
+{
+	features->x_resolution = wacom_calc_hid_res(features->x_max,
+						    features->x_phy,
+						    features->unit,
+						    features->unitExpo);
+	features->y_resolution = wacom_calc_hid_res(features->y_max,
+						    features->y_phy,
+						    features->unit,
+						    features->unitExpo);
+}
+
+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 wacom *wacom;
+	struct wacom_wac *wacom_wac;
+	struct wacom_features *features;
+	int error;
+
+	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_data);
+	features = &wacom_wac->features;
+	features->pktlen = wacom_compute_pktlen(hdev);
+	if (features->pktlen > WACOM_PKGLEN_MAX) {
+		error = -EINVAL;
+		goto fail1;
+	}
+
+	if (features->check_for_hid_type && features->hid_type != hdev->type) {
+		error = -ENODEV;
+		goto fail1;
+	}
+
+	wacom->usbdev = dev;
+	wacom->intf = intf;
+	mutex_init(&wacom->lock);
+	INIT_WORK(&wacom->work, wacom_wireless_work);
+
+	/* 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 */
+	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 (PacketSize
+	 * of WACOM_PKGLEN_BBTOUCH3), override the table values.
+	 */
+	if (features->type >= INTUOS5S && features->type <= INTUOSHT) {
+		if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
+			features->device_type = BTN_TOOL_FINGER;
+
+			features->x_max = 4096;
+			features->y_max = 4096;
+		} else {
+			features->device_type = BTN_TOOL_PEN;
+		}
+	}
+
+	/*
+	 * 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;
+	}
+
+	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 = -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) {
+		/* Append the device type to the name */
+		if (features->device_type != BTN_TOOL_FINGER)
+			strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
+		else if (features->touch_max)
+			strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX);
+		else
+			strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
+
+		error = wacom_add_shared_data(hdev);
+		if (error)
+			goto fail1;
+	}
+
+	error = wacom_initialize_leds(wacom);
+	if (error)
+		goto fail2;
+
+	if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
+		error = wacom_register_inputs(wacom);
+		if (error)
+			goto fail3;
+	}
+
+	/* Note that if query fails it is not a hard failure */
+	wacom_query_tablet_data(hdev, features);
+
+	/* Regular HID work starts now */
+	error = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+	if (error) {
+		hid_err(hdev, "hw start failed\n");
+		goto fail4;
+	}
+
+	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;
+	}
+
+	return 0;
+
+ fail4:	wacom_unregister_inputs(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_remove(struct hid_device *hdev)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+
+	hid_hw_stop(hdev);
+
+	cancel_work_sync(&wacom->work);
+	wacom_unregister_inputs(wacom);
+	wacom_destroy_battery(wacom);
+	wacom_destroy_leds(wacom);
+	wacom_remove_shared_data(&wacom->wacom_wac);
+
+	hid_set_drvdata(hdev, NULL);
+	kfree(wacom);
+}
+
+static int wacom_resume(struct hid_device *hdev)
+{
+	struct wacom *wacom = hid_get_drvdata(hdev);
+	struct wacom_features *features = &wacom->wacom_wac.features;
+
+	mutex_lock(&wacom->lock);
+
+	/* switch to wacom mode first */
+	wacom_query_tablet_data(hdev, features);
+	wacom_led_control(wacom);
+
+	mutex_unlock(&wacom->lock);
+
+	return 0;
+}
+
+static int wacom_reset_resume(struct hid_device *hdev)
+{
+	return wacom_resume(hdev);
+}
+
+static struct hid_driver wacom_driver = {
+	.name =		"wacom",
+	.id_table =	wacom_ids,
+	.probe =	wacom_probe,
+	.remove =	wacom_remove,
+#ifdef CONFIG_PM
+	.resume =	wacom_resume,
+	.reset_resume =	wacom_reset_resume,
+#endif
+	.raw_event =	wacom_raw_event,
+};
+module_hid_driver(wacom_driver);
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
new file mode 100644
index 0000000..d62e320
--- /dev/null
+++ b/drivers/hid/wacom_wac.c
@@ -0,0 +1,2534 @@
+/*
+ * drivers/input/tablet/wacom_wac.c
+ *
+ *  USB Wacom tablet support - Wacom specific code
+ *
+ */
+
+/*
+ * 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.
+ */
+
+#include "wacom_wac.h"
+#include "wacom.h"
+#include <linux/input/mt.h>
+#include <linux/hid.h>
+
+/* resolution for penabled devices */
+#define WACOM_PL_RES		20
+#define WACOM_PENPRTN_RES	40
+#define WACOM_VOLITO_RES	50
+#define WACOM_GRAPHIRE_RES	80
+#define WACOM_INTUOS_RES	100
+#define WACOM_INTUOS3_RES	200
+
+/* 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
+
+static int wacom_penpartner_irq(struct wacom_wac *wacom)
+{
+	unsigned char *data = wacom->data;
+	struct input_dev *input = wacom->input;
+
+	switch (data[0]) {
+	case 1:
+		if (data[5] & 0x80) {
+			wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+			wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID;
+			input_report_key(input, wacom->tool[0], 1);
+			input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
+			input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
+			input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
+			input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127);
+			input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -127));
+			input_report_key(input, BTN_STYLUS, (data[5] & 0x40));
+		} else {
+			input_report_key(input, wacom->tool[0], 0);
+			input_report_abs(input, ABS_MISC, 0); /* report tool id */
+			input_report_abs(input, ABS_PRESSURE, -1);
+			input_report_key(input, BTN_TOUCH, 0);
+		}
+		break;
+
+	case 2:
+		input_report_key(input, BTN_TOOL_PEN, 1);
+		input_report_abs(input, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
+		input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
+		input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
+		input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127);
+		input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
+		input_report_key(input, BTN_STYLUS, (data[5] & 0x40));
+		break;
+
+	default:
+		dev_dbg(input->dev.parent,
+			"%s: received unknown report #%d\n", __func__, data[0]);
+		return 0;
+        }
+
+	return 1;
+}
+
+static int wacom_pl_irq(struct wacom_wac *wacom)
+{
+	struct wacom_features *features = &wacom->features;
+	unsigned char *data = wacom->data;
+	struct input_dev *input = wacom->input;
+	int prox, pressure;
+
+	if (data[0] != WACOM_REPORT_PENABLED) {
+		dev_dbg(input->dev.parent,
+			"%s: received unknown report #%d\n", __func__, data[0]);
+		return 0;
+	}
+
+	prox = data[1] & 0x40;
+
+	if (prox) {
+		wacom->id[0] = ERASER_DEVICE_ID;
+		pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
+		if (features->pressure_max > 255)
+			pressure = (pressure << 1) | ((data[4] >> 6) & 1);
+		pressure += (features->pressure_max + 1) / 2;
+
+		/*
+		 * if going from out of proximity into proximity select between the eraser
+		 * and the pen based on the state of the stylus2 button, choose eraser if
+		 * pressed else choose pen. if not a proximity change from out to in, send
+		 * an out of proximity for previous tool then a in for new tool.
+		 */
+		if (!wacom->tool[0]) {
+			/* Eraser bit set for DTF */
+			if (data[1] & 0x10)
+				wacom->tool[1] = BTN_TOOL_RUBBER;
+			else
+				/* Going into proximity select tool */
+				wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+		} else {
+			/* was entered with stylus2 pressed */
+			if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
+				/* report out proximity for previous tool */
+				input_report_key(input, wacom->tool[1], 0);
+				input_sync(input);
+				wacom->tool[1] = BTN_TOOL_PEN;
+				return 0;
+			}
+		}
+		if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+			/* Unknown tool selected default to pen tool */
+			wacom->tool[1] = BTN_TOOL_PEN;
+			wacom->id[0] = STYLUS_DEVICE_ID;
+		}
+		input_report_key(input, wacom->tool[1], prox); /* report in proximity for tool */
+		input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
+		input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
+		input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
+		input_report_abs(input, ABS_PRESSURE, pressure);
+
+		input_report_key(input, BTN_TOUCH, data[4] & 0x08);
+		input_report_key(input, BTN_STYLUS, data[4] & 0x10);
+		/* Only allow the stylus2 button to be reported for the pen tool. */
+		input_report_key(input, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
+	} else {
+		/* report proximity-out of a (valid) tool */
+		if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+			/* Unknown tool selected default to pen tool */
+			wacom->tool[1] = BTN_TOOL_PEN;
+		}
+		input_report_key(input, wacom->tool[1], prox);
+	}
+
+	wacom->tool[0] = prox; /* Save proximity state */
+	return 1;
+}
+
+static int wacom_ptu_irq(struct wacom_wac *wacom)
+{
+	unsigned char *data = wacom->data;
+	struct input_dev *input = wacom->input;
+
+	if (data[0] != WACOM_REPORT_PENABLED) {
+		dev_dbg(input->dev.parent,
+			"%s: received unknown report #%d\n", __func__, data[0]);
+		return 0;
+	}
+
+	if (data[1] & 0x04) {
+		input_report_key(input, BTN_TOOL_RUBBER, data[1] & 0x20);
+		input_report_key(input, BTN_TOUCH, data[1] & 0x08);
+		wacom->id[0] = ERASER_DEVICE_ID;
+	} else {
+		input_report_key(input, BTN_TOOL_PEN, data[1] & 0x20);
+		input_report_key(input, BTN_TOUCH, data[1] & 0x01);
+		wacom->id[0] = STYLUS_DEVICE_ID;
+	}
+	input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
+	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, le16_to_cpup((__le16 *)&data[6]));
+	input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+	input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
+	return 1;
+}
+
+static int wacom_dtu_irq(struct wacom_wac *wacom)
+{
+	unsigned char *data = wacom->data;
+	struct input_dev *input = wacom->input;
+	int prox = data[1] & 0x20;
+
+	dev_dbg(input->dev.parent,
+		"%s: received report #%d", __func__, data[0]);
+
+	if (prox) {
+		/* Going into proximity select tool */
+		wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+		if (wacom->tool[0] == BTN_TOOL_PEN)
+			wacom->id[0] = STYLUS_DEVICE_ID;
+		else
+			wacom->id[0] = ERASER_DEVICE_ID;
+	}
+	input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+	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] & 0x01) << 8) | data[6]);
+	input_report_key(input, BTN_TOUCH, data[1] & 0x05);
+	if (!prox) /* out-prox */
+		wacom->id[0] = 0;
+	input_report_key(input, wacom->tool[0], prox);
+	input_report_abs(input, ABS_MISC, wacom->id[0]);
+	return 1;
+}
+
+static int wacom_dtus_irq(struct wacom_wac *wacom)
+{
+	char *data = wacom->data;
+	struct input_dev *input = wacom->input;
+	unsigned short prox, pressure = 0;
+
+	if (data[0] != WACOM_REPORT_DTUS && data[0] != WACOM_REPORT_DTUSPAD) {
+		dev_dbg(input->dev.parent,
+			"%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);
+		return 1;
+	} else {
+		prox = data[1] & 0x80;
+		if (prox) {
+			switch ((data[1] >> 3) & 3) {
+			case 1: /* Rubber */
+				wacom->tool[0] = BTN_TOOL_RUBBER;
+				wacom->id[0] = ERASER_DEVICE_ID;
+				break;
+
+			case 2: /* Pen */
+				wacom->tool[0] = BTN_TOOL_PEN;
+				wacom->id[0] = STYLUS_DEVICE_ID;
+				break;
+			}
+		}
+
+		input_report_key(input, BTN_STYLUS, data[1] & 0x20);
+		input_report_key(input, BTN_STYLUS2, data[1] & 0x40);
+		input_report_abs(input, ABS_X, get_unaligned_be16(&data[3]));
+		input_report_abs(input, ABS_Y, get_unaligned_be16(&data[5]));
+		pressure = ((data[1] & 0x03) << 8) | (data[2] & 0xff);
+		input_report_abs(input, ABS_PRESSURE, pressure);
+		input_report_key(input, BTN_TOUCH, pressure > 10);
+
+		if (!prox) /* out-prox */
+			wacom->id[0] = 0;
+		input_report_key(input, wacom->tool[0], prox);
+		input_report_abs(input, ABS_MISC, wacom->id[0]);
+		return 1;
+	}
+}
+
+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 prox;
+	int rw = 0;
+	int retval = 0;
+
+	if (data[0] != WACOM_REPORT_PENABLED) {
+		dev_dbg(input->dev.parent,
+			"%s: received unknown report #%d\n", __func__, data[0]);
+		goto exit;
+	}
+
+	prox = data[1] & 0x80;
+	if (prox || wacom->id[0]) {
+		if (prox) {
+			switch ((data[1] >> 5) & 3) {
+
+			case 0:	/* Pen */
+				wacom->tool[0] = BTN_TOOL_PEN;
+				wacom->id[0] = STYLUS_DEVICE_ID;
+				break;
+
+			case 1: /* Rubber */
+				wacom->tool[0] = BTN_TOOL_RUBBER;
+				wacom->id[0] = ERASER_DEVICE_ID;
+				break;
+
+			case 2: /* Mouse with wheel */
+				input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
+				/* fall through */
+
+			case 3: /* Mouse without wheel */
+				wacom->tool[0] = BTN_TOOL_MOUSE;
+				wacom->id[0] = CURSOR_DEVICE_ID;
+				break;
+			}
+		}
+		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));
+			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);
+		} else {
+			input_report_key(input, BTN_LEFT, data[1] & 0x01);
+			input_report_key(input, BTN_RIGHT, data[1] & 0x02);
+			if (features->type == WACOM_G4 ||
+					features->type == WACOM_MO) {
+				input_report_abs(input, ABS_DISTANCE, data[6] & 0x3f);
+				rw = (data[7] & 0x04) - (data[7] & 0x03);
+			} else {
+				input_report_abs(input, ABS_DISTANCE, data[7] & 0x3f);
+				rw = -(signed char)data[6];
+			}
+			input_report_rel(input, REL_WHEEL, rw);
+		}
+
+		if (!prox)
+			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_sync(input); /* sync last event */
+	}
+
+	/* send pad data */
+	switch (features->type) {
+	case WACOM_G4:
+		prox = data[7] & 0xf8;
+		if (prox || wacom->id[1]) {
+			wacom->id[1] = PAD_DEVICE_ID;
+			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(pad_input, REL_WHEEL, rw);
+			if (!prox)
+				wacom->id[1] = 0;
+			input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
+			retval = 1;
+		}
+		break;
+
+	case WACOM_MO:
+		prox = (data[7] & 0xf8) || data[8];
+		if (prox || wacom->id[1]) {
+			wacom->id[1] = PAD_DEVICE_ID;
+			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;
+	}
+exit:
+	return retval;
+}
+
+static int wacom_intuos_inout(struct wacom_wac *wacom)
+{
+	struct wacom_features *features = &wacom->features;
+	unsigned char *data = wacom->data;
+	struct input_dev *input = wacom->input;
+	int idx = 0;
+
+	/* tool number */
+	if (features->type == INTUOS)
+		idx = data[1] & 0x01;
+
+	/* Enter report */
+	if ((data[1] & 0xfc) == 0xc0) {
+		if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
+			wacom->shared->stylus_in_proximity = true;
+
+		/* serial number of the tool */
+		wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
+			(data[4] << 20) + (data[5] << 12) +
+			(data[6] << 4) + (data[7] >> 4);
+
+		wacom->id[idx] = (data[2] << 4) | (data[3] >> 4) |
+			((data[7] & 0x0f) << 20) | ((data[8] & 0xf0) << 12);
+
+		switch (wacom->id[idx]) {
+		case 0x812: /* Inking pen */
+		case 0x801: /* Intuos3 Inking pen */
+		case 0x120802: /* Intuos4/5 Inking Pen */
+		case 0x012:
+			wacom->tool[idx] = BTN_TOOL_PENCIL;
+			break;
+
+		case 0x822: /* Pen */
+		case 0x842:
+		case 0x852:
+		case 0x823: /* Intuos3 Grip Pen */
+		case 0x813: /* Intuos3 Classic Pen */
+		case 0x885: /* Intuos3 Marker Pen */
+		case 0x802: /* Intuos4/5 13HD/24HD General Pen */
+		case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */
+		case 0x022:
+		case 0x100804: /* Intuos4/5 13HD/24HD Art Pen */
+		case 0x140802: /* Intuos4/5 13HD/24HD Classic Pen */
+		case 0x160802: /* Cintiq 13HD Pro Pen */
+		case 0x180802: /* DTH2242 Pen */
+		case 0x100802: /* Intuos4/5 13HD/24HD General Pen */
+			wacom->tool[idx] = BTN_TOOL_PEN;
+			break;
+
+		case 0x832: /* Stroke pen */
+		case 0x032:
+			wacom->tool[idx] = BTN_TOOL_BRUSH;
+			break;
+
+		case 0x007: /* Mouse 4D and 2D */
+		case 0x09c:
+		case 0x094:
+		case 0x017: /* Intuos3 2D Mouse */
+		case 0x806: /* Intuos4 Mouse */
+			wacom->tool[idx] = BTN_TOOL_MOUSE;
+			break;
+
+		case 0x096: /* Lens cursor */
+		case 0x097: /* Intuos3 Lens cursor */
+		case 0x006: /* Intuos4 Lens cursor */
+			wacom->tool[idx] = BTN_TOOL_LENS;
+			break;
+
+		case 0x82a: /* Eraser */
+		case 0x85a:
+		case 0x91a:
+		case 0xd1a:
+		case 0x0fa:
+		case 0x82b: /* Intuos3 Grip Pen Eraser */
+		case 0x81b: /* Intuos3 Classic Pen Eraser */
+		case 0x91b: /* Intuos3 Airbrush Eraser */
+		case 0x80c: /* Intuos4/5 13HD/24HD Marker Pen Eraser */
+		case 0x80a: /* Intuos4/5 13HD/24HD General Pen Eraser */
+		case 0x90a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
+		case 0x14080a: /* Intuos4/5 13HD/24HD Classic Pen Eraser */
+		case 0x10090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
+		case 0x10080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */
+		case 0x16080a: /* Cintiq 13HD Pro Pen Eraser */
+		case 0x18080a: /* DTH2242 Eraser */
+		case 0x10080a: /* Intuos4/5 13HD/24HD General Pen Eraser */
+			wacom->tool[idx] = BTN_TOOL_RUBBER;
+			break;
+
+		case 0xd12:
+		case 0x912:
+		case 0x112:
+		case 0x913: /* Intuos3 Airbrush */
+		case 0x902: /* Intuos4/5 13HD/24HD Airbrush */
+		case 0x100902: /* Intuos4/5 13HD/24HD Airbrush */
+			wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
+			break;
+
+		default: /* Unknown tool */
+			wacom->tool[idx] = BTN_TOOL_PEN;
+			break;
+		}
+		return 1;
+	}
+
+	/* older I4 styli don't work with new Cintiqs */
+	if (!((wacom->id[idx] >> 20) & 0x01) &&
+			(features->type == WACOM_21UX2))
+		return 1;
+
+	/* Range Report */
+	if ((data[1] & 0xfe) == 0x20) {
+		input_report_key(input, BTN_TOUCH, 0);
+		input_report_abs(input, ABS_PRESSURE, 0);
+		input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max);
+		if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
+			wacom->shared->stylus_in_proximity = true;
+	}
+
+	/* Exit report */
+	if ((data[1] & 0xfe) == 0x80) {
+		if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
+			wacom->shared->stylus_in_proximity = false;
+
+		/*
+		 * Reset all states otherwise we lose the initial states
+		 * when in-prox next time
+		 */
+		input_report_abs(input, ABS_X, 0);
+		input_report_abs(input, ABS_Y, 0);
+		input_report_abs(input, ABS_DISTANCE, 0);
+		input_report_abs(input, ABS_TILT_X, 0);
+		input_report_abs(input, ABS_TILT_Y, 0);
+		if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
+			input_report_key(input, BTN_LEFT, 0);
+			input_report_key(input, BTN_MIDDLE, 0);
+			input_report_key(input, BTN_RIGHT, 0);
+			input_report_key(input, BTN_SIDE, 0);
+			input_report_key(input, BTN_EXTRA, 0);
+			input_report_abs(input, ABS_THROTTLE, 0);
+			input_report_abs(input, ABS_RZ, 0);
+		} else {
+			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, BTN_TOUCH, 0);
+			input_report_abs(input, ABS_WHEEL, 0);
+			if (features->type >= INTUOS3S)
+				input_report_abs(input, ABS_Z, 0);
+		}
+		input_report_key(input, wacom->tool[idx], 0);
+		input_report_abs(input, ABS_MISC, 0); /* reset tool id */
+		input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+		wacom->id[idx] = 0;
+		return 2;
+	}
+	return 0;
+}
+
+static void wacom_intuos_general(struct wacom_wac *wacom)
+{
+	struct wacom_features *features = &wacom->features;
+	unsigned char *data = wacom->data;
+	struct input_dev *input = wacom->input;
+	unsigned int t;
+
+	/* general pen packet */
+	if ((data[1] & 0xb8) == 0xa0) {
+		t = (data[6] << 2) | ((data[7] >> 6) & 3);
+		if (features->type >= INTUOS4S && features->type <= CINTIQ_HYBRID) {
+			t = (t << 1) | (data[1] & 1);
+		}
+		input_report_abs(input, ABS_PRESSURE, t);
+		input_report_abs(input, ABS_TILT_X,
+				((data[7] << 1) & 0x7e) | (data[8] >> 7));
+		input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f);
+		input_report_key(input, BTN_STYLUS, data[1] & 2);
+		input_report_key(input, BTN_STYLUS2, data[1] & 4);
+		input_report_key(input, BTN_TOUCH, t > 10);
+	}
+
+	/* airbrush second packet */
+	if ((data[1] & 0xbc) == 0xb4) {
+		input_report_abs(input, ABS_WHEEL,
+				(data[6] << 2) | ((data[7] >> 6) & 3));
+		input_report_abs(input, ABS_TILT_X,
+				((data[7] << 1) & 0x7e) | (data[8] >> 7));
+		input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f);
+	}
+}
+
+static int wacom_intuos_irq(struct wacom_wac *wacom)
+{
+	struct wacom_features *features = &wacom->features;
+	unsigned char *data = wacom->data;
+	struct input_dev *input = wacom->input;
+	unsigned int t;
+	int idx = 0, result;
+
+	if (data[0] != WACOM_REPORT_PENABLED &&
+	    data[0] != WACOM_REPORT_INTUOSREAD &&
+	    data[0] != WACOM_REPORT_INTUOSWRITE &&
+	    data[0] != WACOM_REPORT_INTUOSPAD &&
+	    data[0] != WACOM_REPORT_INTUOS5PAD) {
+		dev_dbg(input->dev.parent,
+			"%s: received unknown report #%d\n", __func__, data[0]);
+                return 0;
+	}
+
+	/* tool number */
+	if (features->type == INTUOS)
+		idx = data[1] & 0x01;
+
+	/* pad packets. Works as a second tool and is always in prox */
+	if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) {
+		input = wacom->pad_input;
+		if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
+			input_report_key(input, BTN_0, (data[2] & 0x01));
+			input_report_key(input, BTN_1, (data[3] & 0x01));
+			input_report_key(input, BTN_2, (data[3] & 0x02));
+			input_report_key(input, BTN_3, (data[3] & 0x04));
+			input_report_key(input, BTN_4, (data[3] & 0x08));
+			input_report_key(input, BTN_5, (data[3] & 0x10));
+			input_report_key(input, BTN_6, (data[3] & 0x20));
+			if (data[1] & 0x80) {
+				input_report_abs(input, ABS_WHEEL, (data[1] & 0x7f));
+			} else {
+				/* Out of proximity, clear wheel value. */
+				input_report_abs(input, ABS_WHEEL, 0);
+			}
+			if (features->type != INTUOS4S) {
+				input_report_key(input, BTN_7, (data[3] & 0x40));
+				input_report_key(input, BTN_8, (data[3] & 0x80));
+			}
+			if (data[1] | (data[2] & 0x01) | data[3]) {
+				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+			} else {
+				input_report_abs(input, ABS_MISC, 0);
+			}
+		} else if (features->type == DTK) {
+			input_report_key(input, BTN_0, (data[6] & 0x01));
+			input_report_key(input, BTN_1, (data[6] & 0x02));
+			input_report_key(input, BTN_2, (data[6] & 0x04));
+			input_report_key(input, BTN_3, (data[6] & 0x08));
+			input_report_key(input, BTN_4, (data[6] & 0x10));
+			input_report_key(input, BTN_5, (data[6] & 0x20));
+			if (data[6] & 0x3f) {
+				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+			} else {
+				input_report_abs(input, ABS_MISC, 0);
+			}
+		} else if (features->type == WACOM_13HD) {
+			input_report_key(input, BTN_0, (data[3] & 0x01));
+			input_report_key(input, BTN_1, (data[4] & 0x01));
+			input_report_key(input, BTN_2, (data[4] & 0x02));
+			input_report_key(input, BTN_3, (data[4] & 0x04));
+			input_report_key(input, BTN_4, (data[4] & 0x08));
+			input_report_key(input, BTN_5, (data[4] & 0x10));
+			input_report_key(input, BTN_6, (data[4] & 0x20));
+			input_report_key(input, BTN_7, (data[4] & 0x40));
+			input_report_key(input, BTN_8, (data[4] & 0x80));
+			if ((data[3] & 0x01) | data[4]) {
+				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+			} else {
+				input_report_abs(input, ABS_MISC, 0);
+			}
+		} else if (features->type == WACOM_24HD) {
+			input_report_key(input, BTN_0, (data[6] & 0x01));
+			input_report_key(input, BTN_1, (data[6] & 0x02));
+			input_report_key(input, BTN_2, (data[6] & 0x04));
+			input_report_key(input, BTN_3, (data[6] & 0x08));
+			input_report_key(input, BTN_4, (data[6] & 0x10));
+			input_report_key(input, BTN_5, (data[6] & 0x20));
+			input_report_key(input, BTN_6, (data[6] & 0x40));
+			input_report_key(input, BTN_7, (data[6] & 0x80));
+			input_report_key(input, BTN_8, (data[8] & 0x01));
+			input_report_key(input, BTN_9, (data[8] & 0x02));
+			input_report_key(input, BTN_A, (data[8] & 0x04));
+			input_report_key(input, BTN_B, (data[8] & 0x08));
+			input_report_key(input, BTN_C, (data[8] & 0x10));
+			input_report_key(input, BTN_X, (data[8] & 0x20));
+			input_report_key(input, BTN_Y, (data[8] & 0x40));
+			input_report_key(input, BTN_Z, (data[8] & 0x80));
+
+			/*
+			 * Three "buttons" are available on the 24HD which are
+			 * physically implemented as a touchstrip. Each button
+			 * is approximately 3 bits wide with a 2 bit spacing.
+			 * The raw touchstrip bits are stored at:
+			 *    ((data[3] & 0x1f) << 8) | data[4])
+			 */
+			input_report_key(input, KEY_PROG1, data[4] & 0x07);
+			input_report_key(input, KEY_PROG2, data[4] & 0xE0);
+			input_report_key(input, KEY_PROG3, data[3] & 0x1C);
+
+			if (data[1] & 0x80) {
+				input_report_abs(input, ABS_WHEEL, (data[1] & 0x7f));
+			} else {
+				/* Out of proximity, clear wheel value. */
+				input_report_abs(input, ABS_WHEEL, 0);
+			}
+
+			if (data[2] & 0x80) {
+				input_report_abs(input, ABS_THROTTLE, (data[2] & 0x7f));
+			} else {
+				/* Out of proximity, clear second wheel value. */
+				input_report_abs(input, ABS_THROTTLE, 0);
+			}
+
+			if (data[1] | data[2] | (data[3] & 0x1f) | data[4] | data[6] | data[8]) {
+				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+			} else {
+				input_report_abs(input, ABS_MISC, 0);
+			}
+		} else if (features->type == CINTIQ_HYBRID) {
+			/*
+			 * Do not send hardware buttons under Android. They
+			 * are already sent to the system through GPIO (and
+			 * have different meaning).
+			 */
+			input_report_key(input, BTN_1, (data[4] & 0x01));
+			input_report_key(input, BTN_2, (data[4] & 0x02));
+			input_report_key(input, BTN_3, (data[4] & 0x04));
+			input_report_key(input, BTN_4, (data[4] & 0x08));
+
+			input_report_key(input, BTN_5, (data[4] & 0x10));  /* Right  */
+			input_report_key(input, BTN_6, (data[4] & 0x20));  /* Up     */
+			input_report_key(input, BTN_7, (data[4] & 0x40));  /* Left   */
+			input_report_key(input, BTN_8, (data[4] & 0x80));  /* Down   */
+			input_report_key(input, BTN_0, (data[3] & 0x01));  /* Center */
+		} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
+			int i;
+
+			/* Touch ring mode switch has no capacitive sensor */
+			input_report_key(input, BTN_0, (data[3] & 0x01));
+
+			/*
+			 * ExpressKeys on Intuos5/Intuos Pro have a capacitive sensor in
+			 * addition to the mechanical switch. Switch data is
+			 * stored in data[4], capacitive data in data[5].
+			 */
+			for (i = 0; i < 8; i++)
+				input_report_key(input, BTN_1 + i, data[4] & (1 << i));
+
+			if (data[2] & 0x80) {
+				input_report_abs(input, ABS_WHEEL, (data[2] & 0x7f));
+			} else {
+				/* Out of proximity, clear wheel value. */
+				input_report_abs(input, ABS_WHEEL, 0);
+			}
+
+			if (data[2] | (data[3] & 0x01) | data[4] | data[5]) {
+				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+			} else {
+				input_report_abs(input, ABS_MISC, 0);
+			}
+		} else {
+			if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
+				input_report_key(input, BTN_0, (data[5] & 0x01));
+				input_report_key(input, BTN_1, (data[6] & 0x01));
+				input_report_key(input, BTN_2, (data[6] & 0x02));
+				input_report_key(input, BTN_3, (data[6] & 0x04));
+				input_report_key(input, BTN_4, (data[6] & 0x08));
+				input_report_key(input, BTN_5, (data[6] & 0x10));
+				input_report_key(input, BTN_6, (data[6] & 0x20));
+				input_report_key(input, BTN_7, (data[6] & 0x40));
+				input_report_key(input, BTN_8, (data[6] & 0x80));
+				input_report_key(input, BTN_9, (data[7] & 0x01));
+				input_report_key(input, BTN_A, (data[8] & 0x01));
+				input_report_key(input, BTN_B, (data[8] & 0x02));
+				input_report_key(input, BTN_C, (data[8] & 0x04));
+				input_report_key(input, BTN_X, (data[8] & 0x08));
+				input_report_key(input, BTN_Y, (data[8] & 0x10));
+				input_report_key(input, BTN_Z, (data[8] & 0x20));
+				input_report_key(input, BTN_BASE, (data[8] & 0x40));
+				input_report_key(input, BTN_BASE2, (data[8] & 0x80));
+
+				if (features->type == WACOM_22HD) {
+					input_report_key(input, KEY_PROG1, data[9] & 0x01);
+					input_report_key(input, KEY_PROG2, data[9] & 0x02);
+					input_report_key(input, KEY_PROG3, data[9] & 0x04);
+				}
+			} else {
+				input_report_key(input, BTN_0, (data[5] & 0x01));
+				input_report_key(input, BTN_1, (data[5] & 0x02));
+				input_report_key(input, BTN_2, (data[5] & 0x04));
+				input_report_key(input, BTN_3, (data[5] & 0x08));
+				input_report_key(input, BTN_4, (data[6] & 0x01));
+				input_report_key(input, BTN_5, (data[6] & 0x02));
+				input_report_key(input, BTN_6, (data[6] & 0x04));
+				input_report_key(input, BTN_7, (data[6] & 0x08));
+				input_report_key(input, BTN_8, (data[5] & 0x10));
+				input_report_key(input, BTN_9, (data[6] & 0x10));
+			}
+			input_report_abs(input, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
+			input_report_abs(input, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
+
+			if ((data[5] & 0x1f) | data[6] | (data[1] & 0x1f) |
+				data[2] | (data[3] & 0x1f) | data[4] | data[8] |
+				(data[7] & 0x01)) {
+				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+			} else {
+				input_report_abs(input, ABS_MISC, 0);
+			}
+		}
+                return 1;
+	}
+
+	/* process in/out prox events */
+	result = wacom_intuos_inout(wacom);
+	if (result)
+                return result - 1;
+
+	/* don't proceed if we don't know the ID */
+	if (!wacom->id[idx])
+		return 0;
+
+	/* Only large Intuos support Lense Cursor */
+	if (wacom->tool[idx] == BTN_TOOL_LENS &&
+	    (features->type == INTUOS3 ||
+	     features->type == INTUOS3S ||
+	     features->type == INTUOS4 ||
+	     features->type == INTUOS4S ||
+	     features->type == INTUOS5 ||
+	     features->type == INTUOS5S ||
+	     features->type == INTUOSPM ||
+	     features->type == INTUOSPS)) {
+
+		return 0;
+	}
+
+	/* Cintiq doesn't send data when RDY bit isn't set */
+	if (features->type == CINTIQ && !(data[1] & 0x40))
+                 return 0;
+
+	if (features->type >= INTUOS3S) {
+		input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
+		input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
+		input_report_abs(input, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+	} else {
+		input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[2]));
+		input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[4]));
+		input_report_abs(input, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
+	}
+
+	/* process general packets */
+	wacom_intuos_general(wacom);
+
+	/* 4D mouse, 2D mouse, marker pen rotation, tilt mouse, or Lens cursor packets */
+	if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0 || (data[1] & 0xbc) == 0xac) {
+
+		if (data[1] & 0x02) {
+			/* Rotation packet */
+			if (features->type >= INTUOS3S) {
+				/* I3 marker pen rotation */
+				t = (data[6] << 3) | ((data[7] >> 5) & 7);
+				t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+					((t-1) / 2 + 450)) : (450 - t / 2) ;
+				input_report_abs(input, ABS_Z, t);
+			} else {
+				/* 4D mouse rotation packet */
+				t = (data[6] << 3) | ((data[7] >> 5) & 7);
+				input_report_abs(input, ABS_RZ, (data[7] & 0x20) ?
+					((t - 1) / 2) : -t / 2);
+			}
+
+		} else if (!(data[1] & 0x10) && features->type < INTUOS3S) {
+			/* 4D mouse packet */
+			input_report_key(input, BTN_LEFT,   data[8] & 0x01);
+			input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
+			input_report_key(input, BTN_RIGHT,  data[8] & 0x04);
+
+			input_report_key(input, BTN_SIDE,   data[8] & 0x20);
+			input_report_key(input, BTN_EXTRA,  data[8] & 0x10);
+			t = (data[6] << 2) | ((data[7] >> 6) & 3);
+			input_report_abs(input, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
+
+		} else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
+			/* I4 mouse */
+			if (features->type >= INTUOS4S && features->type <= INTUOSPL) {
+				input_report_key(input, BTN_LEFT,   data[6] & 0x01);
+				input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
+				input_report_key(input, BTN_RIGHT,  data[6] & 0x04);
+				input_report_rel(input, REL_WHEEL, ((data[7] & 0x80) >> 7)
+						 - ((data[7] & 0x40) >> 6));
+				input_report_key(input, BTN_SIDE,   data[6] & 0x08);
+				input_report_key(input, BTN_EXTRA,  data[6] & 0x10);
+
+				input_report_abs(input, ABS_TILT_X,
+					((data[7] << 1) & 0x7e) | (data[8] >> 7));
+				input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f);
+			} else {
+				/* 2D mouse packet */
+				input_report_key(input, BTN_LEFT,   data[8] & 0x04);
+				input_report_key(input, BTN_MIDDLE, data[8] & 0x08);
+				input_report_key(input, BTN_RIGHT,  data[8] & 0x10);
+				input_report_rel(input, REL_WHEEL, (data[8] & 0x01)
+						 - ((data[8] & 0x02) >> 1));
+
+				/* I3 2D mouse side buttons */
+				if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
+					input_report_key(input, BTN_SIDE,   data[8] & 0x40);
+					input_report_key(input, BTN_EXTRA,  data[8] & 0x20);
+				}
+			}
+		} else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
+				features->type == INTUOS4L || features->type == INTUOS5L ||
+				features->type == INTUOSPL) &&
+			   wacom->tool[idx] == BTN_TOOL_LENS) {
+			/* Lens cursor packets */
+			input_report_key(input, BTN_LEFT,   data[8] & 0x01);
+			input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
+			input_report_key(input, BTN_RIGHT,  data[8] & 0x04);
+			input_report_key(input, BTN_SIDE,   data[8] & 0x10);
+			input_report_key(input, BTN_EXTRA,  data[8] & 0x08);
+		}
+	}
+
+	input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */
+	input_report_key(input, wacom->tool[idx], 1);
+	input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+	return 1;
+}
+
+static int int_dist(int x1, int y1, int x2, int y2)
+{
+	int x = x2 - x1;
+	int y = y2 - y1;
+
+	return int_sqrt(x*x + y*y);
+}
+
+static int wacom_24hdt_irq(struct wacom_wac *wacom)
+{
+	struct input_dev *input = wacom->input;
+	unsigned char *data = wacom->data;
+	int i;
+	int current_num_contacts = data[61];
+	int contacts_to_send = 0;
+
+	/*
+	 * First packet resets the counter since only the first
+	 * packet in series will have non-zero current_num_contacts.
+	 */
+	if (current_num_contacts)
+		wacom->num_contacts_left = current_num_contacts;
+
+	/* There are at most 4 contacts per packet */
+	contacts_to_send = min(4, wacom->num_contacts_left);
+
+	for (i = 0; i < contacts_to_send; i++) {
+		int offset = (WACOM_BYTES_PER_24HDT_PACKET * i) + 1;
+		bool touch = data[offset] & 0x1 && !wacom->shared->stylus_in_proximity;
+		int slot = input_mt_get_slot_by_key(input, data[offset + 1]);
+
+		if (slot < 0)
+			continue;
+		input_mt_slot(input, slot);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+
+		if (touch) {
+			int t_x = get_unaligned_le16(&data[offset + 2]);
+			int c_x = get_unaligned_le16(&data[offset + 4]);
+			int t_y = get_unaligned_le16(&data[offset + 6]);
+			int c_y = get_unaligned_le16(&data[offset + 8]);
+			int w = get_unaligned_le16(&data[offset + 10]);
+			int h = get_unaligned_le16(&data[offset + 12]);
+
+			input_report_abs(input, ABS_MT_POSITION_X, t_x);
+			input_report_abs(input, ABS_MT_POSITION_Y, t_y);
+			input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h));
+			input_report_abs(input, ABS_MT_WIDTH_MAJOR, min(w, h) + int_dist(t_x, t_y, c_x, c_y));
+			input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
+			input_report_abs(input, ABS_MT_ORIENTATION, w > h);
+		}
+	}
+	input_mt_report_pointer_emulation(input, true);
+
+	wacom->num_contacts_left -= contacts_to_send;
+	if (wacom->num_contacts_left <= 0)
+		wacom->num_contacts_left = 0;
+
+	return 1;
+}
+
+static int wacom_mt_touch(struct wacom_wac *wacom)
+{
+	struct input_dev *input = wacom->input;
+	unsigned char *data = wacom->data;
+	int i;
+	int current_num_contacts = data[2];
+	int contacts_to_send = 0;
+	int x_offset = 0;
+
+	/* MTTPC does not support Height and Width */
+	if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
+		x_offset = -4;
+
+	/*
+	 * First packet resets the counter since only the first
+	 * packet in series will have non-zero current_num_contacts.
+	 */
+	if (current_num_contacts)
+		wacom->num_contacts_left = current_num_contacts;
+
+	/* There are at most 5 contacts per packet */
+	contacts_to_send = min(5, wacom->num_contacts_left);
+
+	for (i = 0; i < contacts_to_send; i++) {
+		int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
+		bool touch = data[offset] & 0x1;
+		int id = get_unaligned_le16(&data[offset + 1]);
+		int slot = input_mt_get_slot_by_key(input, id);
+
+		if (slot < 0)
+			continue;
+
+		input_mt_slot(input, slot);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+		if (touch) {
+			int x = get_unaligned_le16(&data[offset + x_offset + 7]);
+			int y = get_unaligned_le16(&data[offset + x_offset + 9]);
+			input_report_abs(input, ABS_MT_POSITION_X, x);
+			input_report_abs(input, ABS_MT_POSITION_Y, y);
+		}
+	}
+	input_mt_report_pointer_emulation(input, true);
+
+	wacom->num_contacts_left -= contacts_to_send;
+	if (wacom->num_contacts_left < 0)
+		wacom->num_contacts_left = 0;
+
+	return 1;
+}
+
+static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
+{
+	struct input_dev *input = wacom->input;
+	unsigned char *data = wacom->data;
+	int contact_with_no_pen_down_count = 0;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		int p = data[1] & (1 << i);
+		bool touch = p && !wacom->shared->stylus_in_proximity;
+
+		input_mt_slot(input, i);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+		if (touch) {
+			int x = le16_to_cpup((__le16 *)&data[i * 2 + 2]) & 0x7fff;
+			int y = le16_to_cpup((__le16 *)&data[i * 2 + 6]) & 0x7fff;
+
+			input_report_abs(input, ABS_MT_POSITION_X, x);
+			input_report_abs(input, ABS_MT_POSITION_Y, y);
+			contact_with_no_pen_down_count++;
+		}
+	}
+	input_mt_report_pointer_emulation(input, true);
+
+	/* keep touch state for pen event */
+	wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
+
+	return 1;
+}
+
+static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
+{
+	unsigned char *data = wacom->data;
+	struct input_dev *input = wacom->input;
+	bool prox;
+	int x = 0, y = 0;
+
+	if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
+		return 0;
+
+	if (!wacom->shared->stylus_in_proximity) {
+		if (len == WACOM_PKGLEN_TPC1FG) {
+			prox = data[0] & 0x01;
+			x = get_unaligned_le16(&data[1]);
+			y = get_unaligned_le16(&data[3]);
+		} else if (len == WACOM_PKGLEN_TPC1FG_B) {
+			prox = data[2] & 0x01;
+			x = get_unaligned_le16(&data[3]);
+			y = get_unaligned_le16(&data[5]);
+		} else {
+			prox = data[1] & 0x01;
+			x = le16_to_cpup((__le16 *)&data[2]);
+			y = le16_to_cpup((__le16 *)&data[4]);
+		}
+	} else
+		/* force touch out when pen is in prox */
+		prox = 0;
+
+	if (prox) {
+		input_report_abs(input, ABS_X, x);
+		input_report_abs(input, ABS_Y, y);
+	}
+	input_report_key(input, BTN_TOUCH, prox);
+
+	/* keep touch state for pen events */
+	wacom->shared->touch_down = prox;
+
+	return 1;
+}
+
+static int wacom_tpc_pen(struct wacom_wac *wacom)
+{
+	unsigned char *data = wacom->data;
+	struct input_dev *input = wacom->input;
+	bool prox = data[1] & 0x20;
+
+	if (!wacom->shared->stylus_in_proximity) /* first in prox */
+		/* Going into proximity select tool */
+		wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+
+	/* keep pen state for touch events */
+	wacom->shared->stylus_in_proximity = prox;
+
+	/* send pen events only when touch is up or forced out */
+	if (!wacom->shared->touch_down) {
+		input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+		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_key(input, BTN_TOUCH, data[1] & 0x05);
+		input_report_key(input, wacom->tool[0], prox);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
+{
+	unsigned char *data = wacom->data;
+
+	dev_dbg(wacom->input->dev.parent,
+		"%s: received report #%d\n", __func__, data[0]);
+
+	switch (len) {
+	case WACOM_PKGLEN_TPC1FG:
+		return wacom_tpc_single_touch(wacom, len);
+
+	case WACOM_PKGLEN_TPC2FG:
+		return wacom_tpc_mt_touch(wacom);
+
+	case WACOM_PKGLEN_PENABLED:
+		return wacom_tpc_pen(wacom);
+
+	default:
+		switch (data[0]) {
+		case WACOM_REPORT_TPC1FG:
+		case WACOM_REPORT_TPCHID:
+		case WACOM_REPORT_TPCST:
+		case WACOM_REPORT_TPC1FGE:
+			return wacom_tpc_single_touch(wacom, len);
+
+		case WACOM_REPORT_TPCMT:
+		case WACOM_REPORT_TPCMT2:
+			return wacom_mt_touch(wacom);
+
+		case WACOM_REPORT_PENABLED:
+			return wacom_tpc_pen(wacom);
+		}
+	}
+
+	return 0;
+}
+
+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;
+
+	if (data[0] != 0x02)
+	    return 0;
+
+	for (i = 0; i < 2; i++) {
+		int offset = (data[1] & 0x80) ? (8 * i) : (9 * i);
+		bool touch = data[offset + 3] & 0x80;
+
+		/*
+		 * Touch events need to be disabled while stylus is
+		 * in proximity because user's hand is resting on touchpad
+		 * and sending unwanted events.  User expects tablet buttons
+		 * to continue working though.
+		 */
+		touch = touch && !wacom->shared->stylus_in_proximity;
+
+		input_mt_slot(input, i);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+		if (touch) {
+			int x = get_unaligned_be16(&data[offset + 3]) & 0x7ff;
+			int y = get_unaligned_be16(&data[offset + 5]) & 0x7ff;
+			if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
+				x <<= 5;
+				y <<= 5;
+			}
+			input_report_abs(input, ABS_MT_POSITION_X, x);
+			input_report_abs(input, ABS_MT_POSITION_Y, y);
+		}
+	}
+
+	input_mt_report_pointer_emulation(input, true);
+
+	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 1;
+}
+
+static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
+{
+	struct wacom_features *features = &wacom->features;
+	struct input_dev *input = wacom->input;
+	bool touch = data[1] & 0x80;
+	int slot = input_mt_get_slot_by_key(input, data[0]);
+
+	if (slot < 0)
+		return;
+
+	touch = touch && !wacom->shared->stylus_in_proximity;
+
+	input_mt_slot(input, slot);
+	input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+
+	if (touch) {
+		int x = (data[2] << 4) | (data[4] >> 4);
+		int y = (data[3] << 4) | (data[4] & 0x0f);
+		int width, height;
+
+		if (features->type >= INTUOSPS && features->type <= INTUOSPL) {
+			width  = data[5] * 100;
+			height = data[6] * 100;
+		} else {
+			/*
+			 * "a" is a scaled-down area which we assume is
+			 * roughly circular and which can be described as:
+			 * a=(pi*r^2)/C.
+			 */
+			int a = data[5];
+			int x_res = input_abs_get_res(input, ABS_MT_POSITION_X);
+			int y_res = input_abs_get_res(input, ABS_MT_POSITION_Y);
+			width = 2 * int_sqrt(a * WACOM_CONTACT_AREA_SCALE);
+			height = width * y_res / x_res;
+		}
+
+		input_report_abs(input, ABS_MT_POSITION_X, x);
+		input_report_abs(input, ABS_MT_POSITION_Y, y);
+		input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
+		input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
+	}
+}
+
+static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
+{
+	struct input_dev *input = wacom->pad_input;
+	struct wacom_features *features = &wacom->features;
+
+	if (features->type == INTUOSHT) {
+		input_report_key(input, BTN_LEFT, (data[1] & 0x02) != 0);
+		input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0);
+	} else {
+		input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);
+		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_RIGHT, (data[1] & 0x01) != 0);
+}
+
+static int wacom_bpt3_touch(struct wacom_wac *wacom)
+{
+	struct input_dev *input = wacom->input;
+	unsigned char *data = wacom->data;
+	int count = data[1] & 0x07;
+	int i;
+
+	if (data[0] != 0x02)
+	    return 0;
+
+	/* data has up to 7 fixed sized 8-byte messages starting at data[2] */
+	for (i = 0; i < count; i++) {
+		int offset = (8 * i) + 2;
+		int msg_id = data[offset];
+
+		if (msg_id >= 2 && msg_id <= 17)
+			wacom_bpt3_touch_msg(wacom, data + offset);
+		else if (msg_id == 128)
+			wacom_bpt3_button_msg(wacom, data + offset);
+
+	}
+	input_mt_report_pointer_emulation(input, true);
+
+	return 1;
+}
+
+static int wacom_bpt_pen(struct wacom_wac *wacom)
+{
+	struct wacom_features *features = &wacom->features;
+	struct input_dev *input = wacom->input;
+	unsigned char *data = wacom->data;
+	int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0;
+
+	if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_USB)
+	    return 0;
+
+	if (data[0] == WACOM_REPORT_USB) {
+		if (features->type == INTUOSHT && features->touch_max) {
+			input_report_switch(wacom->shared->touch_input,
+					    SW_MUTE_DEVICE, data[8] & 0x40);
+			input_sync(wacom->shared->touch_input);
+		}
+		return 0;
+	}
+
+	prox = (data[1] & 0x20) == 0x20;
+
+	/*
+	 * All reports shared between PEN and RUBBER tool must be
+	 * forced to a known starting value (zero) when transitioning to
+	 * out-of-prox.
+	 *
+	 * If not reset then, to userspace, it will look like lost events
+	 * if new tool comes in-prox with same values as previous tool sent.
+	 *
+	 * Hardware does report zero in most out-of-prox cases but not all.
+	 */
+	if (prox) {
+		if (!wacom->shared->stylus_in_proximity) {
+			if (data[1] & 0x08) {
+				wacom->tool[0] = BTN_TOOL_RUBBER;
+				wacom->id[0] = ERASER_DEVICE_ID;
+			} else {
+				wacom->tool[0] = BTN_TOOL_PEN;
+				wacom->id[0] = STYLUS_DEVICE_ID;
+			}
+			wacom->shared->stylus_in_proximity = true;
+		}
+		x = le16_to_cpup((__le16 *)&data[2]);
+		y = le16_to_cpup((__le16 *)&data[4]);
+		p = le16_to_cpup((__le16 *)&data[6]);
+		/*
+		 * Convert distance from out prox to distance from tablet.
+		 * distance will be greater than distance_max once
+		 * touching and applying pressure; do not report negative
+		 * distance.
+		 */
+		if (data[8] <= features->distance_max)
+			d = features->distance_max - data[8];
+
+		pen = data[1] & 0x01;
+		btn1 = data[1] & 0x02;
+		btn2 = data[1] & 0x04;
+	}
+
+	input_report_key(input, BTN_TOUCH, pen);
+	input_report_key(input, BTN_STYLUS, btn1);
+	input_report_key(input, BTN_STYLUS2, btn2);
+
+	input_report_abs(input, ABS_X, x);
+	input_report_abs(input, ABS_Y, y);
+	input_report_abs(input, ABS_PRESSURE, p);
+	input_report_abs(input, ABS_DISTANCE, d);
+
+	if (!prox) {
+		wacom->id[0] = 0;
+		wacom->shared->stylus_in_proximity = false;
+	}
+
+	input_report_key(input, wacom->tool[0], prox); /* PEN or RUBBER */
+	input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
+
+	return 1;
+}
+
+static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
+{
+	if (len == WACOM_PKGLEN_BBTOUCH)
+		return wacom_bpt_touch(wacom);
+	else if (len == WACOM_PKGLEN_BBTOUCH3)
+		return wacom_bpt3_touch(wacom);
+	else if (len == WACOM_PKGLEN_BBFUN || len == WACOM_PKGLEN_BBPEN)
+		return wacom_bpt_pen(wacom);
+
+	return 0;
+}
+
+static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
+{
+	unsigned char *data = wacom->data;
+	int connected;
+
+	if (len != WACOM_PKGLEN_WIRELESS || data[0] != WACOM_REPORT_WL)
+		return 0;
+
+	connected = data[1] & 0x01;
+	if (connected) {
+		int pid, battery;
+
+		if ((wacom->shared->type == INTUOSHT) &&
+				wacom->shared->touch_max) {
+			input_report_switch(wacom->shared->touch_input,
+					SW_MUTE_DEVICE, data[5] & 0x40);
+			input_sync(wacom->shared->touch_input);
+		}
+
+		pid = get_unaligned_be16(&data[6]);
+		battery = data[5] & 0x3f;
+		if (wacom->pid != pid) {
+			wacom->pid = pid;
+			wacom_schedule_work(wacom);
+		}
+		wacom->battery_capacity = battery;
+	} else if (wacom->pid != 0) {
+		/* disconnected while previously connected */
+		wacom->pid = 0;
+		wacom_schedule_work(wacom);
+		wacom->battery_capacity = 0;
+	}
+
+	return 0;
+}
+
+void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
+{
+	bool sync;
+
+	switch (wacom_wac->features.type) {
+	case PENPARTNER:
+		sync = wacom_penpartner_irq(wacom_wac);
+		break;
+
+	case PL:
+		sync = wacom_pl_irq(wacom_wac);
+		break;
+
+	case WACOM_G4:
+	case GRAPHIRE:
+	case WACOM_MO:
+		sync = wacom_graphire_irq(wacom_wac);
+		break;
+
+	case PTU:
+		sync = wacom_ptu_irq(wacom_wac);
+		break;
+
+	case DTU:
+		sync = wacom_dtu_irq(wacom_wac);
+		break;
+
+	case DTUS:
+		sync = wacom_dtus_irq(wacom_wac);
+		break;
+
+	case INTUOS:
+	case INTUOS3S:
+	case INTUOS3:
+	case INTUOS3L:
+	case INTUOS4S:
+	case INTUOS4:
+	case INTUOS4L:
+	case CINTIQ:
+	case WACOM_BEE:
+	case WACOM_13HD:
+	case WACOM_21UX2:
+	case WACOM_22HD:
+	case WACOM_24HD:
+	case DTK:
+	case CINTIQ_HYBRID:
+		sync = wacom_intuos_irq(wacom_wac);
+		break;
+
+	case WACOM_24HDT:
+		sync = wacom_24hdt_irq(wacom_wac);
+		break;
+
+	case INTUOS5S:
+	case INTUOS5:
+	case INTUOS5L:
+	case INTUOSPS:
+	case INTUOSPM:
+	case INTUOSPL:
+		if (len == WACOM_PKGLEN_BBTOUCH3)
+			sync = wacom_bpt3_touch(wacom_wac);
+		else
+			sync = wacom_intuos_irq(wacom_wac);
+		break;
+
+	case TABLETPC:
+	case TABLETPCE:
+	case TABLETPC2FG:
+	case MTSCREEN:
+	case MTTPC:
+	case MTTPC_B:
+		sync = wacom_tpc_irq(wacom_wac, len);
+		break;
+
+	case BAMBOO_PT:
+	case INTUOSHT:
+		sync = wacom_bpt_irq(wacom_wac, len);
+		break;
+
+	case WIRELESS:
+		sync = wacom_wireless_irq(wacom_wac, len);
+		break;
+
+	default:
+		sync = false;
+		break;
+	}
+
+	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)
+{
+	struct input_dev *input_dev = wacom_wac->input;
+
+	input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
+
+	__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+	__set_bit(BTN_TOOL_PEN, input_dev->keybit);
+	__set_bit(BTN_TOOL_BRUSH, input_dev->keybit);
+	__set_bit(BTN_TOOL_PENCIL, input_dev->keybit);
+	__set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit);
+	__set_bit(BTN_STYLUS, input_dev->keybit);
+	__set_bit(BTN_STYLUS2, input_dev->keybit);
+
+	input_set_abs_params(input_dev, ABS_DISTANCE,
+			     0, wacom_wac->features.distance_max, 0, 0);
+	input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
+	input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
+	input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
+}
+
+static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
+{
+	struct input_dev *input_dev = wacom_wac->input;
+
+	input_set_capability(input_dev, EV_REL, REL_WHEEL);
+
+	wacom_setup_cintiq(wacom_wac);
+
+	__set_bit(BTN_LEFT, input_dev->keybit);
+	__set_bit(BTN_RIGHT, input_dev->keybit);
+	__set_bit(BTN_MIDDLE, input_dev->keybit);
+	__set_bit(BTN_SIDE, input_dev->keybit);
+	__set_bit(BTN_EXTRA, input_dev->keybit);
+	__set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
+	__set_bit(BTN_TOOL_LENS, input_dev->keybit);
+
+	input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
+	input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
+}
+
+void wacom_setup_device_quirks(struct wacom_features *features)
+{
+
+	/* touch device found but size is not defined. use default */
+	if (features->device_type == BTN_TOOL_FINGER && !features->x_max) {
+		features->x_max = 1023;
+		features->y_max = 1023;
+	}
+
+	/* these device have multiple inputs */
+	if (features->type >= WIRELESS ||
+	    (features->type >= INTUOS5S && features->type <= INTUOSHT) ||
+	    (features->oVid && features->oPid))
+		features->quirks |= WACOM_QUIRK_MULTI_INPUT;
+
+	/* quirk for bamboo touch with 2 low res touches */
+	if (features->type == BAMBOO_PT &&
+	    features->pktlen == WACOM_PKGLEN_BBTOUCH) {
+		features->x_max <<= 5;
+		features->y_max <<= 5;
+		features->x_fuzz <<= 5;
+		features->y_fuzz <<= 5;
+		features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES;
+	}
+
+	if (features->type == WIRELESS) {
+
+		/* monitor never has input and pen/touch have delayed create */
+		features->quirks |= WACOM_QUIRK_NO_INPUT;
+
+		/* must be monitor interface if no device_type set */
+		if (!features->device_type)
+			features->quirks |= WACOM_QUIRK_MONITOR;
+	}
+}
+
+static void wacom_abs_set_axis(struct input_dev *input_dev,
+			       struct wacom_wac *wacom_wac)
+{
+	struct wacom_features *features = &wacom_wac->features;
+
+	if (features->device_type == BTN_TOOL_PEN) {
+		input_set_abs_params(input_dev, ABS_X, features->x_min,
+				     features->x_max, features->x_fuzz, 0);
+		input_set_abs_params(input_dev, ABS_Y, features->y_min,
+				     features->y_max, features->y_fuzz, 0);
+		input_set_abs_params(input_dev, ABS_PRESSURE, 0,
+			features->pressure_max, features->pressure_fuzz, 0);
+
+		/* penabled devices have fixed resolution for each model */
+		input_abs_set_res(input_dev, ABS_X, features->x_resolution);
+		input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
+	} else {
+		if (features->touch_max == 1) {
+			input_set_abs_params(input_dev, ABS_X, 0,
+				features->x_max, features->x_fuzz, 0);
+			input_set_abs_params(input_dev, ABS_Y, 0,
+				features->y_max, features->y_fuzz, 0);
+			input_abs_set_res(input_dev, ABS_X,
+					  features->x_resolution);
+			input_abs_set_res(input_dev, ABS_Y,
+					  features->y_resolution);
+		}
+
+		if (features->touch_max > 1) {
+			input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
+				features->x_max, features->x_fuzz, 0);
+			input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
+				features->y_max, features->y_fuzz, 0);
+			input_abs_set_res(input_dev, ABS_MT_POSITION_X,
+					  features->x_resolution);
+			input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
+					  features->y_resolution);
+		}
+	}
+}
+
+int wacom_setup_input_capabilities(struct input_dev *input_dev,
+				   struct wacom_wac *wacom_wac)
+{
+	struct wacom_features *features = &wacom_wac->features;
+
+	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+	__set_bit(ABS_MISC, input_dev->absbit);
+
+	wacom_abs_set_axis(input_dev, wacom_wac);
+
+	switch (features->type) {
+	case WACOM_MO:
+		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
+		/* fall through */
+
+	case WACOM_G4:
+		/* fall through */
+
+	case GRAPHIRE:
+		input_set_capability(input_dev, EV_REL, REL_WHEEL);
+
+		__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:
+		__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
+		wacom_setup_cintiq(wacom_wac);
+		break;
+
+	case WACOM_22HD:
+	case WACOM_21UX2:
+	case WACOM_BEE:
+	case CINTIQ:
+		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;
+
+	case WACOM_13HD:
+		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;
+
+	case INTUOS3:
+	case INTUOS3L:
+	case INTUOS3S:
+		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+		/* fall through */
+
+	case INTUOS:
+		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
+		wacom_setup_intuos(wacom_wac);
+		break;
+
+	case INTUOS5:
+	case INTUOS5L:
+	case INTUOSPM:
+	case INTUOSPL:
+	case INTUOS5S:
+	case INTUOSPS:
+		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
+		if (features->device_type == BTN_TOOL_PEN) {
+			input_set_abs_params(input_dev, ABS_DISTANCE, 0,
+					      features->distance_max,
+					      0, 0);
+
+			input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+
+			wacom_setup_intuos(wacom_wac);
+		} else if (features->device_type == BTN_TOOL_FINGER) {
+			__clear_bit(ABS_MISC, input_dev->absbit);
+
+			input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+			                     0, features->x_max, 0, 0);
+			input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
+			                     0, features->y_max, 0, 0);
+			input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
+		}
+		break;
+
+	case INTUOS4:
+	case INTUOS4L:
+	case INTUOS4S:
+		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+		wacom_setup_intuos(wacom_wac);
+
+		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+		break;
+
+	case WACOM_24HDT:
+		if (features->device_type == BTN_TOOL_FINGER) {
+			input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0);
+			input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, features->x_max, 0, 0);
+			input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR, 0, features->y_max, 0, 0);
+			input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+		}
+		/* fall through */
+
+	case MTSCREEN:
+	case MTTPC:
+	case MTTPC_B:
+	case TABLETPC2FG:
+		if (features->device_type == BTN_TOOL_FINGER && features->touch_max > 1)
+			input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_DIRECT);
+		/* fall through */
+
+	case TABLETPC:
+	case TABLETPCE:
+		__clear_bit(ABS_MISC, input_dev->absbit);
+
+		__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
+		if (features->device_type != BTN_TOOL_PEN)
+			break;  /* no need to process stylus stuff */
+
+		/* fall through */
+
+	case DTUS:
+	case PL:
+	case DTU:
+		__set_bit(BTN_TOOL_PEN, input_dev->keybit);
+		__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+		__set_bit(BTN_STYLUS, input_dev->keybit);
+		__set_bit(BTN_STYLUS2, input_dev->keybit);
+
+		__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+		break;
+
+	case PTU:
+		__set_bit(BTN_STYLUS2, input_dev->keybit);
+		/* fall through */
+
+	case PENPARTNER:
+		__set_bit(BTN_TOOL_PEN, input_dev->keybit);
+		__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+		__set_bit(BTN_STYLUS, input_dev->keybit);
+
+		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+		break;
+
+	case INTUOSHT:
+		if (features->touch_max &&
+		    features->device_type == BTN_TOOL_FINGER) {
+			input_dev->evbit[0] |= BIT_MASK(EV_SW);
+			__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
+		}
+		/* fall through */
+
+	case BAMBOO_PT:
+		__clear_bit(ABS_MISC, input_dev->absbit);
+
+		if (features->device_type == BTN_TOOL_FINGER) {
+
+			if (features->touch_max) {
+				if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
+					input_set_abs_params(input_dev,
+						     ABS_MT_TOUCH_MAJOR,
+						     0, features->x_max, 0, 0);
+					input_set_abs_params(input_dev,
+						     ABS_MT_TOUCH_MINOR,
+						     0, features->y_max, 0, 0);
+				}
+				input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
+			} else {
+				/* buttons/keys only interface */
+				__clear_bit(ABS_X, input_dev->absbit);
+				__clear_bit(ABS_Y, input_dev->absbit);
+				__clear_bit(BTN_TOUCH, input_dev->keybit);
+			}
+		} else if (features->device_type == BTN_TOOL_PEN) {
+			__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+			__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+			__set_bit(BTN_TOOL_PEN, input_dev->keybit);
+			__set_bit(BTN_STYLUS, input_dev->keybit);
+			__set_bit(BTN_STYLUS2, input_dev->keybit);
+			input_set_abs_params(input_dev, ABS_DISTANCE, 0,
+					      features->distance_max,
+					      0, 0);
+		}
+		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 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);
+
+		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);
+		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 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);
+
+		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", 5040, 3780, 255, 0,
+	  PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
+static const struct wacom_features wacom_features_0x10 =
+	{ "Wacom Graphire", 10206, 7422, 511, 63,
+	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+static const struct wacom_features wacom_features_0x11 =
+	{ "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", 13918, 10206, 511, 63,
+	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+static const struct wacom_features wacom_features_0x13 =
+	{ "Wacom Graphire3", 10208, 7424, 511, 63,
+	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+static const struct wacom_features wacom_features_0x14 =
+	{ "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", 10208, 7424, 511, 63,
+	  WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+static const struct wacom_features wacom_features_0x16 =
+	{ "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", 14760, 9225, 511, 63,
+	  WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x18 =
+	{ "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", 16704, 12064, 511, 63,
+	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+static const struct wacom_features wacom_features_0x60 =
+	{ "Wacom Volito", 5104, 3712, 511, 63,
+	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
+static const struct wacom_features wacom_features_0x61 =
+	{ "Wacom PenStation2", 3250, 2320, 255, 63,
+	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
+static const struct wacom_features wacom_features_0x62 =
+	{ "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", 3248, 2320, 511, 63,
+	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
+static const struct wacom_features wacom_features_0x64 =
+	{ "Wacom PenPartner2", 3250, 2320, 511, 63,
+	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
+static const struct wacom_features wacom_features_0x65 =
+	{ "Wacom Bamboo", 14760, 9225, 511, 63,
+	  WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x69 =
+	{ "Wacom Bamboo1", 5104, 3712, 511, 63,
+	  GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
+static const struct wacom_features wacom_features_0x6A =
+	{ "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", 21648, 13530, 1023, 63,
+	  GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x20 =
+	{ "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", 20320, 16240, 1023, 31,
+	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x22 =
+	{ "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", 30480, 31680, 1023, 31,
+	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x24 =
+	{ "Wacom Intuos 12x18", 45720, 31680, 1023, 31,
+	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x30 =
+	{ "Wacom PL400", 5408, 4056, 255, 0,
+	  PL, WACOM_PL_RES, WACOM_PL_RES };
+static const struct wacom_features wacom_features_0x31 =
+	{ "Wacom PL500", 6144, 4608, 255, 0,
+	  PL, WACOM_PL_RES, WACOM_PL_RES };
+static const struct wacom_features wacom_features_0x32 =
+	{ "Wacom PL600", 6126, 4604, 255, 0,
+	  PL, WACOM_PL_RES, WACOM_PL_RES };
+static const struct wacom_features wacom_features_0x33 =
+	{ "Wacom PL600SX", 6260, 5016, 255, 0,
+	  PL, WACOM_PL_RES, WACOM_PL_RES };
+static const struct wacom_features wacom_features_0x34 =
+	{ "Wacom PL550", 6144, 4608, 511, 0,
+	  PL, WACOM_PL_RES, WACOM_PL_RES };
+static const struct wacom_features wacom_features_0x35 =
+	{ "Wacom PL800", 7220, 5780, 511, 0,
+	  PL, WACOM_PL_RES, WACOM_PL_RES };
+static const struct wacom_features wacom_features_0x37 =
+	{ "Wacom PL700", 6758, 5406, 511, 0,
+	  PL, WACOM_PL_RES, WACOM_PL_RES };
+static const struct wacom_features wacom_features_0x38 =
+	{ "Wacom PL510", 6282, 4762, 511, 0,
+	  PL, WACOM_PL_RES, WACOM_PL_RES };
+static const struct wacom_features wacom_features_0x39 =
+	{ "Wacom DTU710", 34080, 27660, 511, 0,
+	  PL, WACOM_PL_RES, WACOM_PL_RES };
+static const struct wacom_features wacom_features_0xC4 =
+	{ "Wacom DTF521", 6282, 4762, 511, 0,
+	  PL, WACOM_PL_RES, WACOM_PL_RES };
+static const struct wacom_features wacom_features_0xC0 =
+	{ "Wacom DTF720", 6858, 5506, 511, 0,
+	  PL, WACOM_PL_RES, WACOM_PL_RES };
+static const struct wacom_features wacom_features_0xC2 =
+	{ "Wacom DTF720a", 6858, 5506, 511, 0,
+	  PL, WACOM_PL_RES, WACOM_PL_RES };
+static const struct wacom_features wacom_features_0x03 =
+	{ "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", 12700, 10600, 1023, 31,
+	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x42 =
+	{ "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", 30480, 24060, 1023, 31,
+	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x44 =
+	{ "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", 45720, 31680, 1023, 31,
+	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xB0 =
+	{ "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", 40640, 30480, 1023, 63,
+	  INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0xB2 =
+	{ "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", 60960, 60960, 1023, 63,
+	  INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0xB4 =
+	{ "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", 54204, 31750, 1023, 63,
+	  INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0xB7 =
+	{ "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", 31496, 19685, 2047, 63,
+	  INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0xB9 =
+	{ "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", 65024, 40640, 2047, 63,
+	  INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0xBB =
+	{ "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", 40640, 25400, 2047, 63,
+	  INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x26 =
+	{ "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", 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", 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", 31496, 19685, 2047, 63,
+	  INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x2A =
+	{ "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", 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", 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", 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", 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", 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,
+	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x3F =
+	{ "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", 86680, 54180, 1023, 63,
+	  WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0xC6 =
+	{ "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", 59352, 33648, 1023, 63,
+	  WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
+static const struct wacom_features wacom_features_0xC7 =
+	{ "Wacom DTU1931", 37832, 30305, 511, 0,
+	  PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xCE =
+	{ "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", 34623, 19553, 511, 0,
+	  DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xFB =
+	{ "Wacom DTU1031", 22096, 13960, 511, 0,
+	  DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x57 =
+	{ "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", 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,
+	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0xCC =
+	{ "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", 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", 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,
+	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x90 =
+	{ "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", 26202, 16325, 255, 0,
+	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x97 =
+	{ "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", 26202, 16325, 255, 0,
+	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x9F =
+	{ "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", 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", 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", 26202, 16325, 255, 0,
+	  MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xE6 =
+	{ "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", 25710, 14500, 255, 0,
+	  TABLETPC,    WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xED =
+	{ "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", 26202, 16325, 255, 0,
+	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x100 =
+	{ "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", 26202, 16325, 255, 0,
+	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x10D =
+	{ "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", 27760, 15694, 255, 0,
+	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x10F =
+	{ "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", 26202, 16325, 255, 0,
+	  TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x4001 =
+	{ "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", 11060, 6220, 255, 0,
+	  MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x5000 =
+	{ "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", 29576, 16724, 1023, 0,
+	  MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x47 =
+	{ "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", 0, 0, 0, 0,
+	  WIRELESS, 0, 0, .touch_max = 16 };
+static const struct wacom_features wacom_features_0xD0 =
+	{ "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", 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", 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", 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", 14720, 9200, 1023, 31,
+	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xD5 =
+	{ "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", 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", 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", 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", 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", 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", 14720, 9200, 1023, 31,
+          BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xDE =
+        { "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", 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", 14720, 9225, 1023, 31,
+	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x301 =
+	{ "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", 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", 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", 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", 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_0x309 =
+	{ "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */
+	  .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)						\
+	HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
+	.driver_data = (kernel_ulong_t)&wacom_features_##prod
+
+#define USB_DEVICE_LENOVO(prod)					\
+	HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, prod),			\
+	.driver_data = (kernel_ulong_t)&wacom_features_##prod
+
+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) },
+	{ USB_DEVICE_WACOM(0x13) },
+	{ USB_DEVICE_WACOM(0x14) },
+	{ USB_DEVICE_WACOM(0x15) },
+	{ USB_DEVICE_WACOM(0x16) },
+	{ USB_DEVICE_WACOM(0x17) },
+	{ USB_DEVICE_WACOM(0x18) },
+	{ USB_DEVICE_WACOM(0x19) },
+	{ 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) },
+	{ USB_DEVICE_WACOM(0x33) },
+	{ USB_DEVICE_WACOM(0x34) },
+	{ USB_DEVICE_WACOM(0x35) },
+	{ USB_DEVICE_WACOM(0x37) },
+	{ USB_DEVICE_WACOM(0x38) },
+	{ USB_DEVICE_WACOM(0x39) },
+	{ 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_WACOM(0x5B) },
+	{ 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) },
+	{ 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) },
+	{ USB_DEVICE_WACOM(0xB3) },
+	{ USB_DEVICE_WACOM(0xB4) },
+	{ USB_DEVICE_WACOM(0xB5) },
+	{ USB_DEVICE_WACOM(0xB7) },
+	{ USB_DEVICE_WACOM(0xB8) },
+	{ USB_DEVICE_WACOM(0xB9) },
+	{ USB_DEVICE_WACOM(0xBA) },
+	{ USB_DEVICE_WACOM(0xBB) },
+	{ USB_DEVICE_WACOM(0xBC) },
+	{ USB_DEVICE_WACOM(0xC0) },
+	{ USB_DEVICE_WACOM(0xC2) },
+	{ USB_DEVICE_WACOM(0xC4) },
+	{ USB_DEVICE_WACOM(0xC5) },
+	{ USB_DEVICE_WACOM(0xC6) },
+	{ USB_DEVICE_WACOM(0xC7) },
+	{ USB_DEVICE_WACOM(0xCC) },
+	{ USB_DEVICE_WACOM(0xCE) },
+	{ USB_DEVICE_WACOM(0xD0) },
+	{ USB_DEVICE_WACOM(0xD1) },
+	{ USB_DEVICE_WACOM(0xD2) },
+	{ USB_DEVICE_WACOM(0xD3) },
+	{ USB_DEVICE_WACOM(0xD4) },
+	{ USB_DEVICE_WACOM(0xD5) },
+	{ USB_DEVICE_WACOM(0xD6) },
+	{ USB_DEVICE_WACOM(0xD7) },
+	{ USB_DEVICE_WACOM(0xD8) },
+	{ USB_DEVICE_WACOM(0xDA) },
+	{ USB_DEVICE_WACOM(0xDB) },
+	{ USB_DEVICE_WACOM(0xDD) },
+	{ USB_DEVICE_WACOM(0xDE) },
+	{ USB_DEVICE_WACOM(0xDF) },
+	{ USB_DEVICE_WACOM(0xE2) },
+	{ USB_DEVICE_WACOM(0xE3) },
+	{ USB_DEVICE_WACOM(0xE5) },
+	{ USB_DEVICE_WACOM(0xE6) },
+	{ 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(0x300) },
+	{ USB_DEVICE_WACOM(0x301) },
+	{ USB_DEVICE_WACOM(0x302) },
+	{ USB_DEVICE_WACOM(0x303) },
+	{ USB_DEVICE_WACOM(0x304) },
+	{ 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) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, wacom_ids);
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
new file mode 100644
index 0000000..4c59247
--- /dev/null
+++ b/drivers/hid/wacom_wac.h
@@ -0,0 +1,169 @@
+/*
+ * drivers/input/tablet/wacom_wac.h
+ *
+ * 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.
+ */
+#ifndef WACOM_WAC_H
+#define WACOM_WAC_H
+
+#include <linux/types.h>
+
+/* maximum packet length for USB devices */
+#define WACOM_PKGLEN_MAX	68
+
+#define WACOM_NAME_MAX		64
+
+/* packet length for individual models */
+#define WACOM_PKGLEN_PENPRTN	 7
+#define WACOM_PKGLEN_GRAPHIRE	 8
+#define WACOM_PKGLEN_BBFUN	 9
+#define WACOM_PKGLEN_INTUOS	10
+#define WACOM_PKGLEN_TPC1FG	 5
+#define WACOM_PKGLEN_TPC1FG_B	10
+#define WACOM_PKGLEN_TPC2FG	14
+#define WACOM_PKGLEN_BBTOUCH	20
+#define WACOM_PKGLEN_BBTOUCH3	64
+#define WACOM_PKGLEN_BBPEN	10
+#define WACOM_PKGLEN_WIRELESS	32
+#define WACOM_PKGLEN_MTOUCH	62
+#define WACOM_PKGLEN_MTTPC	40
+#define WACOM_PKGLEN_DTUS	68
+#define WACOM_PKGLEN_PENABLED	 8
+
+/* wacom data size per MT contact */
+#define WACOM_BYTES_PER_MT_PACKET	11
+#define WACOM_BYTES_PER_24HDT_PACKET	14
+
+/* device IDs */
+#define STYLUS_DEVICE_ID	0x02
+#define TOUCH_DEVICE_ID		0x03
+#define CURSOR_DEVICE_ID	0x06
+#define ERASER_DEVICE_ID	0x0A
+#define PAD_DEVICE_ID		0x0F
+
+/* wacom data packet report IDs */
+#define WACOM_REPORT_PENABLED		2
+#define WACOM_REPORT_INTUOSREAD		5
+#define WACOM_REPORT_INTUOSWRITE	6
+#define WACOM_REPORT_INTUOSPAD		12
+#define WACOM_REPORT_INTUOS5PAD		3
+#define WACOM_REPORT_DTUSPAD		21
+#define WACOM_REPORT_TPC1FG		6
+#define WACOM_REPORT_TPC2FG		13
+#define WACOM_REPORT_TPCMT		13
+#define WACOM_REPORT_TPCMT2		3
+#define WACOM_REPORT_TPCHID		15
+#define WACOM_REPORT_TPCST		16
+#define WACOM_REPORT_DTUS		17
+#define WACOM_REPORT_TPC1FGE		18
+#define WACOM_REPORT_24HDT		1
+#define WACOM_REPORT_WL			128
+#define WACOM_REPORT_USB		192
+
+/* device quirks */
+#define WACOM_QUIRK_MULTI_INPUT		0x0001
+#define WACOM_QUIRK_BBTOUCH_LOWRES	0x0002
+#define WACOM_QUIRK_NO_INPUT		0x0004
+#define WACOM_QUIRK_MONITOR		0x0008
+
+enum {
+	PENPARTNER = 0,
+	GRAPHIRE,
+	WACOM_G4,
+	PTU,
+	PL,
+	DTU,
+	DTUS,
+	INTUOS,
+	INTUOS3S,
+	INTUOS3,
+	INTUOS3L,
+	INTUOS4S,
+	INTUOS4,
+	INTUOS4L,
+	INTUOS5S,
+	INTUOS5,
+	INTUOS5L,
+	INTUOSPS,
+	INTUOSPM,
+	INTUOSPL,
+	INTUOSHT,
+	WACOM_21UX2,
+	WACOM_22HD,
+	DTK,
+	WACOM_24HD,
+	CINTIQ_HYBRID,
+	CINTIQ,
+	WACOM_BEE,
+	WACOM_13HD,
+	WACOM_MO,
+	WIRELESS,
+	BAMBOO_PT,
+	WACOM_24HDT,
+	TABLETPC,   /* add new TPC below */
+	TABLETPCE,
+	TABLETPC2FG,
+	MTSCREEN,
+	MTTPC,
+	MTTPC_B,
+	MAX_TYPE
+};
+
+struct wacom_features {
+	const char *name;
+	int x_max;
+	int y_max;
+	int pressure_max;
+	int distance_max;
+	int type;
+	int x_resolution;
+	int y_resolution;
+	int x_min;
+	int y_min;
+	int device_type;
+	int x_phy;
+	int y_phy;
+	unsigned unit;
+	int unitExpo;
+	int x_fuzz;
+	int y_fuzz;
+	int pressure_fuzz;
+	int distance_fuzz;
+	unsigned quirks;
+	unsigned touch_max;
+	int oVid;
+	int oPid;
+	int pktlen;
+	bool check_for_hid_type;
+	int hid_type;
+};
+
+struct wacom_shared {
+	bool stylus_in_proximity;
+	bool touch_down;
+	/* for wireless device to access USB interfaces */
+	unsigned touch_max;
+	int type;
+	struct input_dev *touch_input;
+};
+
+struct wacom_wac {
+	char name[WACOM_NAME_MAX];
+	char pad_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;
+};
+
+#endif
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
index bed7cbf..cd9c79e 100644
--- a/drivers/input/tablet/Kconfig
+++ b/drivers/input/tablet/Kconfig
@@ -73,20 +73,4 @@ 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.
-
 endif
diff --git a/drivers/input/tablet/Makefile b/drivers/input/tablet/Makefile
index 3f6c252..cc3bc17 100644
--- a/drivers/input/tablet/Makefile
+++ b/drivers/input/tablet/Makefile
@@ -2,12 +2,9 @@
 # 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
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
deleted file mode 100644
index dd67b7d..0000000
--- a/drivers/input/tablet/wacom.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * drivers/input/tablet/wacom.h
- *
- *  USB Wacom tablet support
- *
- *  Copyright (c) 2000-2004 Vojtech Pavlik	<vojtech@....cz>
- *  Copyright (c) 2000 Andreas Bach Aaen	<abach@...fanet.dk>
- *  Copyright (c) 2000 Clifford Wolf		<clifford@...fford.at>
- *  Copyright (c) 2000 Sam Mosel		<sam.mosel@...puter.org>
- *  Copyright (c) 2000 James E. Blair		<corvus@....org>
- *  Copyright (c) 2000 Daniel Egger		<egger@...e.de>
- *  Copyright (c) 2001 Frederic Lepied		<flepied@...drakesoft.com>
- *  Copyright (c) 2004 Panagiotis Issaris	<panagiotis.issaris@...h.kuleuven.ac.be>
- *  Copyright (c) 2002-2011 Ping Cheng		<pingc@...om.com>
- *
- *  ChangeLog:
- *      v0.1 (vp)  - Initial release
- *      v0.2 (aba) - Support for all buttons / combinations
- *      v0.3 (vp)  - Support for Intuos added
- *	v0.4 (sm)  - Support for more Intuos models, menustrip
- *			relative mode, proximity.
- *	v0.5 (vp)  - Big cleanup, nifty features removed,
- *			they belong in userspace
- *	v1.8 (vp)  - Submit URB only when operating, moved to CVS,
- *			use input_report_key instead of report_btn and
- *			other cleanups
- *	v1.11 (vp) - Add URB ->dev setting for new kernels
- *	v1.11 (jb) - Add support for the 4D Mouse & Lens
- *	v1.12 (de) - Add support for two more inking pen IDs
- *	v1.14 (vp) - Use new USB device id probing scheme.
- *		     Fix Wacom Graphire mouse wheel
- *	v1.18 (vp) - Fix mouse wheel direction
- *		     Make mouse relative
- *      v1.20 (fl) - Report tool id for Intuos devices
- *                 - Multi tools support
- *                 - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...)
- *                 - Add PL models support
- *		   - Fix Wacom Graphire mouse wheel again
- *	v1.21 (vp) - Removed protocol descriptions
- *		   - Added MISC_SERIAL for tool serial numbers
- *	      (gb) - Identify version on module load.
- *    v1.21.1 (fl) - added Graphire2 support
- *    v1.21.2 (fl) - added Intuos2 support
- *                 - added all the PL ids
- *    v1.21.3 (fl) - added another eraser id from Neil Okamoto
- *                 - added smooth filter for Graphire from Peri Hankey
- *                 - added PenPartner support from Olaf van Es
- *                 - new tool ids from Ole Martin Bjoerndalen
- *	v1.29 (pc) - Add support for more tablets
- *		   - Fix pressure reporting
- *	v1.30 (vp) - Merge 2.4 and 2.5 drivers
- *		   - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
- *		   - Cleanups here and there
- *    v1.30.1 (pi) - Added Graphire3 support
- *	v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
- *	v1.43 (pc) - Added support for Cintiq 21UX
- *		   - Fixed a Graphire bug
- *		   - Merged wacom_intuos3_irq into wacom_intuos_irq
- *	v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc.
- *		   - Report Device IDs
- *      v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19
- *                 - Minor data report fix
- *      v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c,
- *		   - where wacom_sys.c deals with system specific code,
- *		   - and wacom_wac.c deals with Wacom specific code
- *		   - Support Intuos3 4x6
- *      v1.47 (pc) - Added support for Bamboo
- *      v1.48 (pc) - Added support for Bamboo1, BambooFun, and Cintiq 12WX
- *      v1.49 (pc) - Added support for USB Tablet PC (0x90, 0x93, and 0x9A)
- *      v1.50 (pc) - Fixed a TabletPC touch bug in 2.6.28
- *      v1.51 (pc) - Added support for Intuos4
- *      v1.52 (pc) - Query Wacom data upon system resume
- *                 - add defines for features->type
- *                 - add new devices (0x9F, 0xE2, and 0XE3)
- */
-
-/*
- * 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.
- */
-#ifndef WACOM_H
-#define WACOM_H
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/usb/input.h>
-#include <linux/power_supply.h>
-#include <asm/unaligned.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.53"
-#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@....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 {
-	struct usb_device *usbdev;
-	struct usb_interface *intf;
-	struct wacom_wac wacom_wac;
-	struct hid_device *hdev;
-	struct mutex lock;
-	struct work_struct work;
-	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;
-	struct power_supply battery;
-};
-
-static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
-{
-	struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
-	schedule_work(&wacom->work);
-}
-
-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
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
deleted file mode 100644
index 9dbb6dd..0000000
--- a/drivers/input/tablet/wacom_sys.c
+++ /dev/null
@@ -1,1257 +0,0 @@
-/*
- * drivers/input/tablet/wacom_sys.c
- *
- *  USB Wacom tablet support - system specific code
- */
-
-/*
- * 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.
- */
-
-#include "wacom_wac.h"
-#include "wacom.h"
-#include <linux/hid.h>
-
-#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_RETRIES		10
-
-static int wacom_get_report(struct hid_device *hdev, u8 type, u8 id,
-			    void *buf, size_t size, unsigned int retries)
-{
-	int retval;
-
-	do {
-		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 hid_device *hdev, u8 type, u8 id,
-			    void *buf, size_t size, unsigned int retries)
-{
-	int retval;
-
-	do {
-		retval = hid_hw_raw_request(hdev, id, buf, size, type,
-				HID_REQ_SET_REPORT);
-	} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
-
-	return retval;
-}
-
-static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
-		u8 *raw_data, int size)
-{
-	struct wacom *wacom = hid_get_drvdata(hdev);
-
-	if (size > WACOM_PKGLEN_MAX)
-		return 1;
-
-	memcpy(wacom->wacom_wac.data, raw_data, size);
-
-	wacom_wac_irq(&wacom->wacom_wac, size);
-
-	return 0;
-}
-
-static int wacom_open(struct input_dev *dev)
-{
-	struct wacom *wacom = input_get_drvdata(dev);
-	int retval;
-
-	mutex_lock(&wacom->lock);
-	retval = hid_hw_open(wacom->hdev);
-	mutex_unlock(&wacom->lock);
-
-	return retval;
-}
-
-static void wacom_close(struct input_dev *dev)
-{
-	struct wacom *wacom = input_get_drvdata(dev);
-
-	mutex_lock(&wacom->lock);
-	hid_hw_close(wacom->hdev);
-	mutex_unlock(&wacom->lock);
-}
-
-/*
- * 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 unit, int exponent)
-{
-	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_feature_mapping(struct hid_device *hdev,
-		struct hid_field *field, struct hid_usage *usage)
-{
-	struct wacom *wacom = hid_get_drvdata(hdev);
-	struct wacom_features *features = &wacom->wacom_wac.features;
-
-	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;
-	}
-}
-
-/*
- * Interface Descriptor of wacom devices can be incomplete and
- * inconsistent so wacom_features table is used to store stylus
- * device's packet lengths, various maximum values, and tablet
- * resolution based on product ID's.
- *
- * For devices that contain 2 interfaces, wacom_features table is
- * inaccurate for the touch interface.  Since the Interface Descriptor
- * for touch interfaces has pretty complete data, this function exists
- * to query tablet for this missing information instead of hard coding in
- * an additional table.
- *
- * A typical Interface Descriptor for a stylus will contain a
- * boot mouse application collection that is not of interest and this
- * function will ignore it.
- *
- * It also contains a digitizer application collection that also is not
- * of interest since any information it contains would be duplicate
- * of what is in wacom_features. Usually it defines a report of an array
- * of bytes that could be used as max length of the stylus packet returned.
- * If it happens to define a Digitizer-Stylus Physical Collection then
- * the X and Y logical values contain valid data but it is ignored.
- *
- * A typical Interface Descriptor for a touch interface will contain a
- * Digitizer-Finger Physical Collection which will define both logical
- * X/Y maximum as well as the physical size of tablet. Since touch
- * interfaces haven't supported pressure or distance, this is enough
- * information to override invalid values in the wacom_features table.
- *
- * Intuos5 touch interface and 3rd gen Bamboo Touch do not contain useful
- * data. We deal with them after returning from this function.
- */
-static void wacom_usage_mapping(struct hid_device *hdev,
-		struct hid_field *field, struct hid_usage *usage)
-{
-	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.
-	*/
-	if (!pen && !finger)
-		return;
-
-	if (finger && !features->touch_max)
-		/* touch device at least supports one touch point */
-		features->touch_max = 1;
-
-	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;
-			}
-		} 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;
-	}
-}
-
-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);
-			}
-		}
-	}
-
-	/* 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 hid_device *hdev, int report_id,
-		int length, int mode)
-{
-	unsigned char *rep_data;
-	int error = -ENOMEM, limit = 0;
-
-	rep_data = kzalloc(length, GFP_KERNEL);
-	if (!rep_data)
-		return error;
-
-	do {
-		rep_data[0] = report_id;
-		rep_data[1] = mode;
-
-		error = wacom_set_report(hdev, HID_FEATURE_REPORT,
-		                         report_id, 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);
-
-	return error < 0 ? error : 0;
-}
-
-/*
- * Switch the tablet into its most-capable mode. Wacom tablets are
- * typically configured to power-up in a mode which sends mouse-like
- * reports to the OS. To get absolute position, pressure data, etc.
- * from the tablet, it is necessary to switch the tablet out of this
- * mode and into one which sends the full range of tablet data.
- */
-static int wacom_query_tablet_data(struct hid_device *hdev,
-		struct wacom_features *features)
-{
-	if (features->device_type == BTN_TOOL_FINGER) {
-		if (features->type > TABLETPC) {
-			/* MT Tablet PC touch */
-			return wacom_set_device_mode(hdev, 3, 4, 4);
-		}
-		else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) {
-			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(hdev, 2, 2, 2);
-		}
-	}
-
-	return 0;
-}
-
-static void wacom_retrieve_hid_descriptor(struct hid_device *hdev,
-					 struct wacom_features *features)
-{
-	struct wacom *wacom = hid_get_drvdata(hdev);
-	struct usb_interface *intf = wacom->intf;
-
-	/* default features */
-	features->device_type = BTN_TOOL_PEN;
-	features->x_fuzz = 4;
-	features->y_fuzz = 4;
-	features->pressure_fuzz = 0;
-	features->distance_fuzz = 0;
-
-	/*
-	 * The wireless device HID is basic and layout conflicts with
-	 * other tablets (monitor and touch interface can look like pen).
-	 * Skip the query for this type and modify defaults based on
-	 * interface number.
-	 */
-	if (features->type == WIRELESS) {
-		if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
-			features->device_type = 0;
-		} else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) {
-			features->device_type = BTN_TOOL_FINGER;
-			features->pktlen = WACOM_PKGLEN_BBTOUCH3;
-		}
-	}
-
-	/* only devices that support touch need to retrieve the info */
-	if (features->type < BAMBOO_PT)
-		return;
-
-	wacom_parse_hid(hdev, features);
-}
-
-struct wacom_hdev_data {
-	struct list_head list;
-	struct kref kref;
-	struct hid_device *dev;
-	struct wacom_shared shared;
-};
-
-static LIST_HEAD(wacom_udev_list);
-static DEFINE_MUTEX(wacom_udev_list_lock);
-
-static bool wacom_are_sibling(struct hid_device *hdev,
-		struct hid_device *sibling)
-{
-	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 (vid == 0 && pid == 0) {
-		vid = hdev->vendor;
-		pid = hdev->product;
-	}
-
-	if (vid != sibling->vendor || pid != sibling->product)
-		return false;
-
-	/* 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 !strncmp(hdev->phys, sibling->phys, n1);
-}
-
-static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
-{
-	struct wacom_hdev_data *data;
-
-	list_for_each_entry(data, &wacom_udev_list, list) {
-		if (wacom_are_sibling(hdev, data->dev)) {
-			kref_get(&data->kref);
-			return data;
-		}
-	}
-
-	return NULL;
-}
-
-static int wacom_add_shared_data(struct hid_device *hdev)
-{
-	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_hdev_data(hdev);
-	if (!data) {
-		data = kzalloc(sizeof(struct wacom_hdev_data), GFP_KERNEL);
-		if (!data) {
-			retval = -ENOMEM;
-			goto out;
-		}
-
-		kref_init(&data->kref);
-		data->dev = hdev;
-		list_add_tail(&data->list, &wacom_udev_list);
-	}
-
-	wacom_wac->shared = &data->shared;
-
-out:
-	mutex_unlock(&wacom_udev_list_lock);
-	return retval;
-}
-
-static void wacom_release_shared_data(struct kref *kref)
-{
-	struct wacom_hdev_data *data =
-		container_of(kref, struct wacom_hdev_data, kref);
-
-	mutex_lock(&wacom_udev_list_lock);
-	list_del(&data->list);
-	mutex_unlock(&wacom_udev_list_lock);
-
-	kfree(data);
-}
-
-static void wacom_remove_shared_data(struct wacom_wac *wacom)
-{
-	struct wacom_hdev_data *data;
-
-	if (wacom->shared) {
-		data = container_of(wacom->shared, struct wacom_hdev_data, shared);
-		kref_put(&data->kref, wacom_release_shared_data);
-		wacom->shared = NULL;
-	}
-}
-
-static int wacom_led_control(struct wacom *wacom)
-{
-	unsigned char *buf;
-	int retval;
-
-	buf = kzalloc(9, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	if (wacom->wacom_wac.features.type >= INTUOS5S &&
-	    wacom->wacom_wac.features.type <= INTUOSPL) {
-		/*
-		 * Touch Ring and crop mark LED luminance may take on
-		 * one of four values:
-		 *    0 = Low; 1 = Medium; 2 = High; 3 = Off
-		 */
-		int ring_led = wacom->led.select[0] & 0x03;
-		int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03;
-		int crop_lum = 0;
-
-		buf[0] = WAC_CMD_LED_CONTROL;
-		buf[1] = (crop_lum << 4) | (ring_lum << 2) | (ring_led);
-	}
-	else {
-		int led = wacom->led.select[0] | 0x4;
-
-		if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
-		    wacom->wacom_wac.features.type == WACOM_24HD)
-			led |= (wacom->led.select[1] << 4) | 0x40;
-
-		buf[0] = WAC_CMD_LED_CONTROL;
-		buf[1] = led;
-		buf[2] = wacom->led.llv;
-		buf[3] = wacom->led.hlv;
-		buf[4] = wacom->led.img_lum;
-	}
-
-	retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
-				  WAC_CMD_LED_CONTROL, buf, 9, WAC_CMD_RETRIES);
-	kfree(buf);
-
-	return retval;
-}
-
-static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img)
-{
-	unsigned char *buf;
-	int i, retval;
-
-	buf = kzalloc(259, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	/* Send 'start' command */
-	buf[0] = WAC_CMD_ICON_START;
-	buf[1] = 1;
-	retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
-				  WAC_CMD_ICON_START, buf, 2, WAC_CMD_RETRIES);
-	if (retval < 0)
-		goto out;
-
-	buf[0] = WAC_CMD_ICON_XFER;
-	buf[1] = button_id & 0x07;
-	for (i = 0; i < 4; i++) {
-		buf[2] = i;
-		memcpy(buf + 3, img + i * 256, 256);
-
-		retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
-					  WAC_CMD_ICON_XFER,
-					  buf, 259, WAC_CMD_RETRIES);
-		if (retval < 0)
-			break;
-	}
-
-	/* Send 'stop' */
-	buf[0] = WAC_CMD_ICON_START;
-	buf[1] = 0;
-	wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, WAC_CMD_ICON_START,
-			 buf, 2, WAC_CMD_RETRIES);
-
-out:
-	kfree(buf);
-	return retval;
-}
-
-static ssize_t wacom_led_select_store(struct device *dev, int set_id,
-				      const char *buf, size_t count)
-{
-	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
-	struct wacom *wacom = hid_get_drvdata(hdev);
-	unsigned int id;
-	int err;
-
-	err = kstrtouint(buf, 10, &id);
-	if (err)
-		return err;
-
-	mutex_lock(&wacom->lock);
-
-	wacom->led.select[set_id] = id & 0x3;
-	err = wacom_led_control(wacom);
-
-	mutex_unlock(&wacom->lock);
-
-	return err < 0 ? err : count;
-}
-
-#define DEVICE_LED_SELECT_ATTR(SET_ID)					\
-static ssize_t wacom_led##SET_ID##_select_store(struct device *dev,	\
-	struct device_attribute *attr, const char *buf, size_t count)	\
-{									\
-	return wacom_led_select_store(dev, SET_ID, buf, count);		\
-}									\
-static ssize_t wacom_led##SET_ID##_select_show(struct device *dev,	\
-	struct device_attribute *attr, char *buf)			\
-{									\
-	struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
-	struct 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,	\
-		    wacom_led##SET_ID##_select_show,			\
-		    wacom_led##SET_ID##_select_store)
-
-DEVICE_LED_SELECT_ATTR(0);
-DEVICE_LED_SELECT_ATTR(1);
-
-static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
-				     const char *buf, size_t count)
-{
-	unsigned int value;
-	int err;
-
-	err = kstrtouint(buf, 10, &value);
-	if (err)
-		return err;
-
-	mutex_lock(&wacom->lock);
-
-	*dest = value & 0x7f;
-	err = wacom_led_control(wacom);
-
-	mutex_unlock(&wacom->lock);
-
-	return err < 0 ? err : count;
-}
-
-#define DEVICE_LUMINANCE_ATTR(name, field)				\
-static ssize_t wacom_##name##_luminance_store(struct device *dev,	\
-	struct device_attribute *attr, const char *buf, size_t count)	\
-{									\
-	struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
-	struct wacom *wacom = hid_get_drvdata(hdev);			\
-									\
-	return wacom_luminance_store(wacom, &wacom->led.field,		\
-				     buf, count);			\
-}									\
-static DEVICE_ATTR(name##_luminance, S_IWUSR,				\
-		   NULL, wacom_##name##_luminance_store)
-
-DEVICE_LUMINANCE_ATTR(status0, llv);
-DEVICE_LUMINANCE_ATTR(status1, hlv);
-DEVICE_LUMINANCE_ATTR(buttons, img_lum);
-
-static ssize_t wacom_button_image_store(struct device *dev, int button_id,
-					const char *buf, size_t count)
-{
-	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
-	struct wacom *wacom = hid_get_drvdata(hdev);
-	int err;
-
-	if (count != 1024)
-		return -EINVAL;
-
-	mutex_lock(&wacom->lock);
-
-	err = wacom_led_putimage(wacom, button_id, buf);
-
-	mutex_unlock(&wacom->lock);
-
-	return err < 0 ? err : count;
-}
-
-#define DEVICE_BTNIMG_ATTR(BUTTON_ID)					\
-static ssize_t wacom_btnimg##BUTTON_ID##_store(struct device *dev,	\
-	struct device_attribute *attr, const char *buf, size_t count)	\
-{									\
-	return wacom_button_image_store(dev, BUTTON_ID, buf, count);	\
-}									\
-static DEVICE_ATTR(button##BUTTON_ID##_rawimg, S_IWUSR,			\
-		   NULL, wacom_btnimg##BUTTON_ID##_store)
-
-DEVICE_BTNIMG_ATTR(0);
-DEVICE_BTNIMG_ATTR(1);
-DEVICE_BTNIMG_ATTR(2);
-DEVICE_BTNIMG_ATTR(3);
-DEVICE_BTNIMG_ATTR(4);
-DEVICE_BTNIMG_ATTR(5);
-DEVICE_BTNIMG_ATTR(6);
-DEVICE_BTNIMG_ATTR(7);
-
-static struct attribute *cintiq_led_attrs[] = {
-	&dev_attr_status_led0_select.attr,
-	&dev_attr_status_led1_select.attr,
-	NULL
-};
-
-static struct attribute_group cintiq_led_attr_group = {
-	.name = "wacom_led",
-	.attrs = cintiq_led_attrs,
-};
-
-static struct attribute *intuos4_led_attrs[] = {
-	&dev_attr_status0_luminance.attr,
-	&dev_attr_status1_luminance.attr,
-	&dev_attr_status_led0_select.attr,
-	&dev_attr_buttons_luminance.attr,
-	&dev_attr_button0_rawimg.attr,
-	&dev_attr_button1_rawimg.attr,
-	&dev_attr_button2_rawimg.attr,
-	&dev_attr_button3_rawimg.attr,
-	&dev_attr_button4_rawimg.attr,
-	&dev_attr_button5_rawimg.attr,
-	&dev_attr_button6_rawimg.attr,
-	&dev_attr_button7_rawimg.attr,
-	NULL
-};
-
-static struct attribute_group intuos4_led_attr_group = {
-	.name = "wacom_led",
-	.attrs = intuos4_led_attrs,
-};
-
-static struct attribute *intuos5_led_attrs[] = {
-	&dev_attr_status0_luminance.attr,
-	&dev_attr_status_led0_select.attr,
-	NULL
-};
-
-static struct attribute_group intuos5_led_attr_group = {
-	.name = "wacom_led",
-	.attrs = intuos5_led_attrs,
-};
-
-static int wacom_initialize_leds(struct wacom *wacom)
-{
-	int error;
-
-	/* Initialize default values */
-	switch (wacom->wacom_wac.features.type) {
-	case INTUOS4S:
-	case INTUOS4:
-	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->hdev->dev.kobj,
-					   &intuos4_led_attr_group);
-		break;
-
-	case WACOM_24HD:
-	case WACOM_21UX2:
-		wacom->led.select[0] = 0;
-		wacom->led.select[1] = 0;
-		wacom->led.llv = 0;
-		wacom->led.hlv = 0;
-		wacom->led.img_lum = 0;
-
-		error = sysfs_create_group(&wacom->hdev->dev.kobj,
-					   &cintiq_led_attr_group);
-		break;
-
-	case INTUOS5S:
-	case INTUOS5:
-	case INTUOS5L:
-	case INTUOSPS:
-	case INTUOSPM:
-	case INTUOSPL:
-		if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN) {
-			wacom->led.select[0] = 0;
-			wacom->led.select[1] = 0;
-			wacom->led.llv = 32;
-			wacom->led.hlv = 0;
-			wacom->led.img_lum = 0;
-
-			error = sysfs_create_group(&wacom->hdev->dev.kobj,
-						  &intuos5_led_attr_group);
-		} else
-			return 0;
-		break;
-
-	default:
-		return 0;
-	}
-
-	if (error) {
-		hid_err(wacom->hdev,
-			"cannot create sysfs group err: %d\n", error);
-		return error;
-	}
-	wacom_led_control(wacom);
-
-	return 0;
-}
-
-static void wacom_destroy_leds(struct wacom *wacom)
-{
-	switch (wacom->wacom_wac.features.type) {
-	case INTUOS4S:
-	case INTUOS4:
-	case INTUOS4L:
-		sysfs_remove_group(&wacom->hdev->dev.kobj,
-				   &intuos4_led_attr_group);
-		break;
-
-	case WACOM_24HD:
-	case WACOM_21UX2:
-		sysfs_remove_group(&wacom->hdev->dev.kobj,
-				   &cintiq_led_attr_group);
-		break;
-
-	case INTUOS5S:
-	case INTUOS5:
-	case INTUOS5L:
-	case INTUOSPS:
-	case INTUOSPM:
-	case INTUOSPL:
-		if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN)
-			sysfs_remove_group(&wacom->hdev->dev.kobj,
-					   &intuos5_led_attr_group);
-		break;
-	}
-}
-
-static enum power_supply_property wacom_battery_props[] = {
-	POWER_SUPPLY_PROP_SCOPE,
-	POWER_SUPPLY_PROP_CAPACITY
-};
-
-static int wacom_battery_get_property(struct power_supply *psy,
-				      enum power_supply_property psp,
-				      union power_supply_propval *val)
-{
-	struct wacom *wacom = container_of(psy, struct wacom, battery);
-	int ret = 0;
-
-	switch (psp) {
-		case POWER_SUPPLY_PROP_SCOPE:
-			val->intval = POWER_SUPPLY_SCOPE_DEVICE;
-			break;
-		case POWER_SUPPLY_PROP_CAPACITY:
-			val->intval =
-				wacom->wacom_wac.battery_capacity * 100 / 31;
-			break;
-		default:
-			ret = -EINVAL;
-			break;
-	}
-
-	return ret;
-}
-
-static int wacom_initialize_battery(struct wacom *wacom)
-{
-	int error = 0;
-
-	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";
-		wacom->battery.type = POWER_SUPPLY_TYPE_BATTERY;
-		wacom->battery.use_for_apm = 0;
-
-		error = power_supply_register(&wacom->hdev->dev,
-					      &wacom->battery);
-
-		if (!error)
-			power_supply_powers(&wacom->battery,
-					    &wacom->hdev->dev);
-	}
-
-	return error;
-}
-
-static void wacom_destroy_battery(struct wacom *wacom)
-{
-	if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR &&
-	    wacom->battery.dev) {
-		power_supply_unregister(&wacom->battery);
-		wacom->battery.dev = NULL;
-	}
-}
-
-static struct input_dev *wacom_allocate_input(struct wacom *wacom)
-{
-	struct input_dev *input_dev;
-	struct hid_device *hdev = wacom->hdev;
-	struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
-
-	input_dev = input_allocate_device();
-	if (!input_dev)
-		return NULL;
-
-	input_dev->name = wacom_wac->name;
-	input_dev->phys = hdev->phys;
-	input_dev->dev.parent = &hdev->dev;
-	input_dev->open = wacom_open;
-	input_dev->close = wacom_close;
-	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 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:
-	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;
-}
-
-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;
-
-	/*
-	 * Regardless if this is a disconnect or a new tablet,
-	 * remove any existing input and battery devices.
-	 */
-
-	wacom_destroy_battery(wacom);
-
-	/* Stylus interface */
-	hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
-	wacom1 = hid_get_drvdata(hdev1);
-	wacom_wac1 = &(wacom1->wacom_wac);
-	wacom_unregister_inputs(wacom1);
-
-	/* Touch interface */
-	hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
-	wacom2 = hid_get_drvdata(hdev2);
-	wacom_wac2 = &(wacom2->wacom_wac);
-	wacom_unregister_inputs(wacom2);
-
-	if (wacom_wac->pid == 0) {
-		hid_info(wacom->hdev, "wireless tablet disconnected\n");
-	} else {
-		const struct hid_device_id *id = wacom_ids;
-
-		hid_info(wacom->hdev, "wireless tablet connected with PID %x\n",
-			 wacom_wac->pid);
-
-		while (id->bus) {
-			if (id->vendor == USB_VENDOR_ID_WACOM &&
-			    id->product == wacom_wac->pid)
-				break;
-			id++;
-		}
-
-		if (!id->bus) {
-			hid_info(wacom->hdev, "ignoring unknown PID.\n");
-			return;
-		}
-
-		/* Stylus interface */
-		wacom_wac1->features =
-			*((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_inputs(wacom1);
-		if (error)
-			goto fail;
-
-		/* Touch interface */
-		if (wacom_wac1->features.touch_max ||
-		    wacom_wac1->features.type == INTUOSHT) {
-			wacom_wac2->features =
-				*((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;
-			if (wacom_wac2->features.touch_max)
-				snprintf(wacom_wac2->name, WACOM_NAME_MAX,
-					 "%s (WL) Finger",wacom_wac2->features.name);
-			else
-				snprintf(wacom_wac2->name, WACOM_NAME_MAX,
-					 "%s (WL) Pad",wacom_wac2->features.name);
-			snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
-				 "%s (WL) Pad", wacom_wac2->features.name);
-			error = wacom_register_inputs(wacom2);
-			if (error)
-				goto fail;
-
-			if (wacom_wac1->features.type == INTUOSHT &&
-			    wacom_wac1->features.touch_max)
-				wacom_wac->shared->touch_input = wacom_wac2->input;
-		}
-
-		error = wacom_initialize_battery(wacom);
-		if (error)
-			goto fail;
-	}
-
-	return;
-
-fail:
-	wacom_unregister_inputs(wacom1);
-	wacom_unregister_inputs(wacom2);
-	return;
-}
-
-/*
- * Not all devices report physical dimensions from HID.
- * Compute the default from hardcoded logical dimension
- * and resolution before driver overwrites them.
- */
-static void wacom_set_default_phy(struct wacom_features *features)
-{
-	if (features->x_resolution) {
-		features->x_phy = (features->x_max * 100) /
-					features->x_resolution;
-		features->y_phy = (features->y_max * 100) /
-					features->y_resolution;
-	}
-}
-
-static void wacom_calculate_res(struct wacom_features *features)
-{
-	features->x_resolution = wacom_calc_hid_res(features->x_max,
-						    features->x_phy,
-						    features->unit,
-						    features->unitExpo);
-	features->y_resolution = wacom_calc_hid_res(features->y_max,
-						    features->y_phy,
-						    features->unit,
-						    features->unitExpo);
-}
-
-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 wacom *wacom;
-	struct wacom_wac *wacom_wac;
-	struct wacom_features *features;
-	int error;
-
-	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_data);
-	features = &wacom_wac->features;
-	features->pktlen = wacom_compute_pktlen(hdev);
-	if (features->pktlen > WACOM_PKGLEN_MAX) {
-		error = -EINVAL;
-		goto fail1;
-	}
-
-	if (features->check_for_hid_type && features->hid_type != hdev->type) {
-		error = -ENODEV;
-		goto fail1;
-	}
-
-	wacom->usbdev = dev;
-	wacom->intf = intf;
-	mutex_init(&wacom->lock);
-	INIT_WORK(&wacom->work, wacom_wireless_work);
-
-	/* 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 */
-	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 (PacketSize
-	 * of WACOM_PKGLEN_BBTOUCH3), override the table values.
-	 */
-	if (features->type >= INTUOS5S && features->type <= INTUOSHT) {
-		if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
-			features->device_type = BTN_TOOL_FINGER;
-
-			features->x_max = 4096;
-			features->y_max = 4096;
-		} else {
-			features->device_type = BTN_TOOL_PEN;
-		}
-	}
-
-	/*
-	 * 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;
-	}
-
-	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 = -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) {
-		/* Append the device type to the name */
-		if (features->device_type != BTN_TOOL_FINGER)
-			strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
-		else if (features->touch_max)
-			strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX);
-		else
-			strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
-
-		error = wacom_add_shared_data(hdev);
-		if (error)
-			goto fail1;
-	}
-
-	error = wacom_initialize_leds(wacom);
-	if (error)
-		goto fail2;
-
-	if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
-		error = wacom_register_inputs(wacom);
-		if (error)
-			goto fail3;
-	}
-
-	/* Note that if query fails it is not a hard failure */
-	wacom_query_tablet_data(hdev, features);
-
-	/* Regular HID work starts now */
-	error = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
-	if (error) {
-		hid_err(hdev, "hw start failed\n");
-		goto fail4;
-	}
-
-	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;
-	}
-
-	return 0;
-
- fail4:	wacom_unregister_inputs(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_remove(struct hid_device *hdev)
-{
-	struct wacom *wacom = hid_get_drvdata(hdev);
-
-	hid_hw_stop(hdev);
-
-	cancel_work_sync(&wacom->work);
-	wacom_unregister_inputs(wacom);
-	wacom_destroy_battery(wacom);
-	wacom_destroy_leds(wacom);
-	wacom_remove_shared_data(&wacom->wacom_wac);
-
-	hid_set_drvdata(hdev, NULL);
-	kfree(wacom);
-}
-
-static int wacom_resume(struct hid_device *hdev)
-{
-	struct wacom *wacom = hid_get_drvdata(hdev);
-	struct wacom_features *features = &wacom->wacom_wac.features;
-
-	mutex_lock(&wacom->lock);
-
-	/* switch to wacom mode first */
-	wacom_query_tablet_data(hdev, features);
-	wacom_led_control(wacom);
-
-	mutex_unlock(&wacom->lock);
-
-	return 0;
-}
-
-static int wacom_reset_resume(struct hid_device *hdev)
-{
-	return wacom_resume(hdev);
-}
-
-static struct hid_driver wacom_driver = {
-	.name =		"wacom",
-	.id_table =	wacom_ids,
-	.probe =	wacom_probe,
-	.remove =	wacom_remove,
-#ifdef CONFIG_PM
-	.resume =	wacom_resume,
-	.reset_resume =	wacom_reset_resume,
-#endif
-	.raw_event =	wacom_raw_event,
-};
-module_hid_driver(wacom_driver);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
deleted file mode 100644
index d62e320..0000000
--- a/drivers/input/tablet/wacom_wac.c
+++ /dev/null
@@ -1,2534 +0,0 @@
-/*
- * drivers/input/tablet/wacom_wac.c
- *
- *  USB Wacom tablet support - Wacom specific code
- *
- */
-
-/*
- * 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.
- */
-
-#include "wacom_wac.h"
-#include "wacom.h"
-#include <linux/input/mt.h>
-#include <linux/hid.h>
-
-/* resolution for penabled devices */
-#define WACOM_PL_RES		20
-#define WACOM_PENPRTN_RES	40
-#define WACOM_VOLITO_RES	50
-#define WACOM_GRAPHIRE_RES	80
-#define WACOM_INTUOS_RES	100
-#define WACOM_INTUOS3_RES	200
-
-/* 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
-
-static int wacom_penpartner_irq(struct wacom_wac *wacom)
-{
-	unsigned char *data = wacom->data;
-	struct input_dev *input = wacom->input;
-
-	switch (data[0]) {
-	case 1:
-		if (data[5] & 0x80) {
-			wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
-			wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID;
-			input_report_key(input, wacom->tool[0], 1);
-			input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
-			input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
-			input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
-			input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127);
-			input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -127));
-			input_report_key(input, BTN_STYLUS, (data[5] & 0x40));
-		} else {
-			input_report_key(input, wacom->tool[0], 0);
-			input_report_abs(input, ABS_MISC, 0); /* report tool id */
-			input_report_abs(input, ABS_PRESSURE, -1);
-			input_report_key(input, BTN_TOUCH, 0);
-		}
-		break;
-
-	case 2:
-		input_report_key(input, BTN_TOOL_PEN, 1);
-		input_report_abs(input, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
-		input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
-		input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
-		input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127);
-		input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
-		input_report_key(input, BTN_STYLUS, (data[5] & 0x40));
-		break;
-
-	default:
-		dev_dbg(input->dev.parent,
-			"%s: received unknown report #%d\n", __func__, data[0]);
-		return 0;
-        }
-
-	return 1;
-}
-
-static int wacom_pl_irq(struct wacom_wac *wacom)
-{
-	struct wacom_features *features = &wacom->features;
-	unsigned char *data = wacom->data;
-	struct input_dev *input = wacom->input;
-	int prox, pressure;
-
-	if (data[0] != WACOM_REPORT_PENABLED) {
-		dev_dbg(input->dev.parent,
-			"%s: received unknown report #%d\n", __func__, data[0]);
-		return 0;
-	}
-
-	prox = data[1] & 0x40;
-
-	if (prox) {
-		wacom->id[0] = ERASER_DEVICE_ID;
-		pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
-		if (features->pressure_max > 255)
-			pressure = (pressure << 1) | ((data[4] >> 6) & 1);
-		pressure += (features->pressure_max + 1) / 2;
-
-		/*
-		 * if going from out of proximity into proximity select between the eraser
-		 * and the pen based on the state of the stylus2 button, choose eraser if
-		 * pressed else choose pen. if not a proximity change from out to in, send
-		 * an out of proximity for previous tool then a in for new tool.
-		 */
-		if (!wacom->tool[0]) {
-			/* Eraser bit set for DTF */
-			if (data[1] & 0x10)
-				wacom->tool[1] = BTN_TOOL_RUBBER;
-			else
-				/* Going into proximity select tool */
-				wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
-		} else {
-			/* was entered with stylus2 pressed */
-			if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
-				/* report out proximity for previous tool */
-				input_report_key(input, wacom->tool[1], 0);
-				input_sync(input);
-				wacom->tool[1] = BTN_TOOL_PEN;
-				return 0;
-			}
-		}
-		if (wacom->tool[1] != BTN_TOOL_RUBBER) {
-			/* Unknown tool selected default to pen tool */
-			wacom->tool[1] = BTN_TOOL_PEN;
-			wacom->id[0] = STYLUS_DEVICE_ID;
-		}
-		input_report_key(input, wacom->tool[1], prox); /* report in proximity for tool */
-		input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
-		input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
-		input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
-		input_report_abs(input, ABS_PRESSURE, pressure);
-
-		input_report_key(input, BTN_TOUCH, data[4] & 0x08);
-		input_report_key(input, BTN_STYLUS, data[4] & 0x10);
-		/* Only allow the stylus2 button to be reported for the pen tool. */
-		input_report_key(input, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
-	} else {
-		/* report proximity-out of a (valid) tool */
-		if (wacom->tool[1] != BTN_TOOL_RUBBER) {
-			/* Unknown tool selected default to pen tool */
-			wacom->tool[1] = BTN_TOOL_PEN;
-		}
-		input_report_key(input, wacom->tool[1], prox);
-	}
-
-	wacom->tool[0] = prox; /* Save proximity state */
-	return 1;
-}
-
-static int wacom_ptu_irq(struct wacom_wac *wacom)
-{
-	unsigned char *data = wacom->data;
-	struct input_dev *input = wacom->input;
-
-	if (data[0] != WACOM_REPORT_PENABLED) {
-		dev_dbg(input->dev.parent,
-			"%s: received unknown report #%d\n", __func__, data[0]);
-		return 0;
-	}
-
-	if (data[1] & 0x04) {
-		input_report_key(input, BTN_TOOL_RUBBER, data[1] & 0x20);
-		input_report_key(input, BTN_TOUCH, data[1] & 0x08);
-		wacom->id[0] = ERASER_DEVICE_ID;
-	} else {
-		input_report_key(input, BTN_TOOL_PEN, data[1] & 0x20);
-		input_report_key(input, BTN_TOUCH, data[1] & 0x01);
-		wacom->id[0] = STYLUS_DEVICE_ID;
-	}
-	input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
-	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, le16_to_cpup((__le16 *)&data[6]));
-	input_report_key(input, BTN_STYLUS, data[1] & 0x02);
-	input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
-	return 1;
-}
-
-static int wacom_dtu_irq(struct wacom_wac *wacom)
-{
-	unsigned char *data = wacom->data;
-	struct input_dev *input = wacom->input;
-	int prox = data[1] & 0x20;
-
-	dev_dbg(input->dev.parent,
-		"%s: received report #%d", __func__, data[0]);
-
-	if (prox) {
-		/* Going into proximity select tool */
-		wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
-		if (wacom->tool[0] == BTN_TOOL_PEN)
-			wacom->id[0] = STYLUS_DEVICE_ID;
-		else
-			wacom->id[0] = ERASER_DEVICE_ID;
-	}
-	input_report_key(input, BTN_STYLUS, data[1] & 0x02);
-	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] & 0x01) << 8) | data[6]);
-	input_report_key(input, BTN_TOUCH, data[1] & 0x05);
-	if (!prox) /* out-prox */
-		wacom->id[0] = 0;
-	input_report_key(input, wacom->tool[0], prox);
-	input_report_abs(input, ABS_MISC, wacom->id[0]);
-	return 1;
-}
-
-static int wacom_dtus_irq(struct wacom_wac *wacom)
-{
-	char *data = wacom->data;
-	struct input_dev *input = wacom->input;
-	unsigned short prox, pressure = 0;
-
-	if (data[0] != WACOM_REPORT_DTUS && data[0] != WACOM_REPORT_DTUSPAD) {
-		dev_dbg(input->dev.parent,
-			"%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);
-		return 1;
-	} else {
-		prox = data[1] & 0x80;
-		if (prox) {
-			switch ((data[1] >> 3) & 3) {
-			case 1: /* Rubber */
-				wacom->tool[0] = BTN_TOOL_RUBBER;
-				wacom->id[0] = ERASER_DEVICE_ID;
-				break;
-
-			case 2: /* Pen */
-				wacom->tool[0] = BTN_TOOL_PEN;
-				wacom->id[0] = STYLUS_DEVICE_ID;
-				break;
-			}
-		}
-
-		input_report_key(input, BTN_STYLUS, data[1] & 0x20);
-		input_report_key(input, BTN_STYLUS2, data[1] & 0x40);
-		input_report_abs(input, ABS_X, get_unaligned_be16(&data[3]));
-		input_report_abs(input, ABS_Y, get_unaligned_be16(&data[5]));
-		pressure = ((data[1] & 0x03) << 8) | (data[2] & 0xff);
-		input_report_abs(input, ABS_PRESSURE, pressure);
-		input_report_key(input, BTN_TOUCH, pressure > 10);
-
-		if (!prox) /* out-prox */
-			wacom->id[0] = 0;
-		input_report_key(input, wacom->tool[0], prox);
-		input_report_abs(input, ABS_MISC, wacom->id[0]);
-		return 1;
-	}
-}
-
-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 prox;
-	int rw = 0;
-	int retval = 0;
-
-	if (data[0] != WACOM_REPORT_PENABLED) {
-		dev_dbg(input->dev.parent,
-			"%s: received unknown report #%d\n", __func__, data[0]);
-		goto exit;
-	}
-
-	prox = data[1] & 0x80;
-	if (prox || wacom->id[0]) {
-		if (prox) {
-			switch ((data[1] >> 5) & 3) {
-
-			case 0:	/* Pen */
-				wacom->tool[0] = BTN_TOOL_PEN;
-				wacom->id[0] = STYLUS_DEVICE_ID;
-				break;
-
-			case 1: /* Rubber */
-				wacom->tool[0] = BTN_TOOL_RUBBER;
-				wacom->id[0] = ERASER_DEVICE_ID;
-				break;
-
-			case 2: /* Mouse with wheel */
-				input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
-				/* fall through */
-
-			case 3: /* Mouse without wheel */
-				wacom->tool[0] = BTN_TOOL_MOUSE;
-				wacom->id[0] = CURSOR_DEVICE_ID;
-				break;
-			}
-		}
-		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));
-			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);
-		} else {
-			input_report_key(input, BTN_LEFT, data[1] & 0x01);
-			input_report_key(input, BTN_RIGHT, data[1] & 0x02);
-			if (features->type == WACOM_G4 ||
-					features->type == WACOM_MO) {
-				input_report_abs(input, ABS_DISTANCE, data[6] & 0x3f);
-				rw = (data[7] & 0x04) - (data[7] & 0x03);
-			} else {
-				input_report_abs(input, ABS_DISTANCE, data[7] & 0x3f);
-				rw = -(signed char)data[6];
-			}
-			input_report_rel(input, REL_WHEEL, rw);
-		}
-
-		if (!prox)
-			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_sync(input); /* sync last event */
-	}
-
-	/* send pad data */
-	switch (features->type) {
-	case WACOM_G4:
-		prox = data[7] & 0xf8;
-		if (prox || wacom->id[1]) {
-			wacom->id[1] = PAD_DEVICE_ID;
-			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(pad_input, REL_WHEEL, rw);
-			if (!prox)
-				wacom->id[1] = 0;
-			input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
-			retval = 1;
-		}
-		break;
-
-	case WACOM_MO:
-		prox = (data[7] & 0xf8) || data[8];
-		if (prox || wacom->id[1]) {
-			wacom->id[1] = PAD_DEVICE_ID;
-			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;
-	}
-exit:
-	return retval;
-}
-
-static int wacom_intuos_inout(struct wacom_wac *wacom)
-{
-	struct wacom_features *features = &wacom->features;
-	unsigned char *data = wacom->data;
-	struct input_dev *input = wacom->input;
-	int idx = 0;
-
-	/* tool number */
-	if (features->type == INTUOS)
-		idx = data[1] & 0x01;
-
-	/* Enter report */
-	if ((data[1] & 0xfc) == 0xc0) {
-		if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
-			wacom->shared->stylus_in_proximity = true;
-
-		/* serial number of the tool */
-		wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
-			(data[4] << 20) + (data[5] << 12) +
-			(data[6] << 4) + (data[7] >> 4);
-
-		wacom->id[idx] = (data[2] << 4) | (data[3] >> 4) |
-			((data[7] & 0x0f) << 20) | ((data[8] & 0xf0) << 12);
-
-		switch (wacom->id[idx]) {
-		case 0x812: /* Inking pen */
-		case 0x801: /* Intuos3 Inking pen */
-		case 0x120802: /* Intuos4/5 Inking Pen */
-		case 0x012:
-			wacom->tool[idx] = BTN_TOOL_PENCIL;
-			break;
-
-		case 0x822: /* Pen */
-		case 0x842:
-		case 0x852:
-		case 0x823: /* Intuos3 Grip Pen */
-		case 0x813: /* Intuos3 Classic Pen */
-		case 0x885: /* Intuos3 Marker Pen */
-		case 0x802: /* Intuos4/5 13HD/24HD General Pen */
-		case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */
-		case 0x022:
-		case 0x100804: /* Intuos4/5 13HD/24HD Art Pen */
-		case 0x140802: /* Intuos4/5 13HD/24HD Classic Pen */
-		case 0x160802: /* Cintiq 13HD Pro Pen */
-		case 0x180802: /* DTH2242 Pen */
-		case 0x100802: /* Intuos4/5 13HD/24HD General Pen */
-			wacom->tool[idx] = BTN_TOOL_PEN;
-			break;
-
-		case 0x832: /* Stroke pen */
-		case 0x032:
-			wacom->tool[idx] = BTN_TOOL_BRUSH;
-			break;
-
-		case 0x007: /* Mouse 4D and 2D */
-		case 0x09c:
-		case 0x094:
-		case 0x017: /* Intuos3 2D Mouse */
-		case 0x806: /* Intuos4 Mouse */
-			wacom->tool[idx] = BTN_TOOL_MOUSE;
-			break;
-
-		case 0x096: /* Lens cursor */
-		case 0x097: /* Intuos3 Lens cursor */
-		case 0x006: /* Intuos4 Lens cursor */
-			wacom->tool[idx] = BTN_TOOL_LENS;
-			break;
-
-		case 0x82a: /* Eraser */
-		case 0x85a:
-		case 0x91a:
-		case 0xd1a:
-		case 0x0fa:
-		case 0x82b: /* Intuos3 Grip Pen Eraser */
-		case 0x81b: /* Intuos3 Classic Pen Eraser */
-		case 0x91b: /* Intuos3 Airbrush Eraser */
-		case 0x80c: /* Intuos4/5 13HD/24HD Marker Pen Eraser */
-		case 0x80a: /* Intuos4/5 13HD/24HD General Pen Eraser */
-		case 0x90a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
-		case 0x14080a: /* Intuos4/5 13HD/24HD Classic Pen Eraser */
-		case 0x10090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
-		case 0x10080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */
-		case 0x16080a: /* Cintiq 13HD Pro Pen Eraser */
-		case 0x18080a: /* DTH2242 Eraser */
-		case 0x10080a: /* Intuos4/5 13HD/24HD General Pen Eraser */
-			wacom->tool[idx] = BTN_TOOL_RUBBER;
-			break;
-
-		case 0xd12:
-		case 0x912:
-		case 0x112:
-		case 0x913: /* Intuos3 Airbrush */
-		case 0x902: /* Intuos4/5 13HD/24HD Airbrush */
-		case 0x100902: /* Intuos4/5 13HD/24HD Airbrush */
-			wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
-			break;
-
-		default: /* Unknown tool */
-			wacom->tool[idx] = BTN_TOOL_PEN;
-			break;
-		}
-		return 1;
-	}
-
-	/* older I4 styli don't work with new Cintiqs */
-	if (!((wacom->id[idx] >> 20) & 0x01) &&
-			(features->type == WACOM_21UX2))
-		return 1;
-
-	/* Range Report */
-	if ((data[1] & 0xfe) == 0x20) {
-		input_report_key(input, BTN_TOUCH, 0);
-		input_report_abs(input, ABS_PRESSURE, 0);
-		input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max);
-		if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
-			wacom->shared->stylus_in_proximity = true;
-	}
-
-	/* Exit report */
-	if ((data[1] & 0xfe) == 0x80) {
-		if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
-			wacom->shared->stylus_in_proximity = false;
-
-		/*
-		 * Reset all states otherwise we lose the initial states
-		 * when in-prox next time
-		 */
-		input_report_abs(input, ABS_X, 0);
-		input_report_abs(input, ABS_Y, 0);
-		input_report_abs(input, ABS_DISTANCE, 0);
-		input_report_abs(input, ABS_TILT_X, 0);
-		input_report_abs(input, ABS_TILT_Y, 0);
-		if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
-			input_report_key(input, BTN_LEFT, 0);
-			input_report_key(input, BTN_MIDDLE, 0);
-			input_report_key(input, BTN_RIGHT, 0);
-			input_report_key(input, BTN_SIDE, 0);
-			input_report_key(input, BTN_EXTRA, 0);
-			input_report_abs(input, ABS_THROTTLE, 0);
-			input_report_abs(input, ABS_RZ, 0);
-		} else {
-			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, BTN_TOUCH, 0);
-			input_report_abs(input, ABS_WHEEL, 0);
-			if (features->type >= INTUOS3S)
-				input_report_abs(input, ABS_Z, 0);
-		}
-		input_report_key(input, wacom->tool[idx], 0);
-		input_report_abs(input, ABS_MISC, 0); /* reset tool id */
-		input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
-		wacom->id[idx] = 0;
-		return 2;
-	}
-	return 0;
-}
-
-static void wacom_intuos_general(struct wacom_wac *wacom)
-{
-	struct wacom_features *features = &wacom->features;
-	unsigned char *data = wacom->data;
-	struct input_dev *input = wacom->input;
-	unsigned int t;
-
-	/* general pen packet */
-	if ((data[1] & 0xb8) == 0xa0) {
-		t = (data[6] << 2) | ((data[7] >> 6) & 3);
-		if (features->type >= INTUOS4S && features->type <= CINTIQ_HYBRID) {
-			t = (t << 1) | (data[1] & 1);
-		}
-		input_report_abs(input, ABS_PRESSURE, t);
-		input_report_abs(input, ABS_TILT_X,
-				((data[7] << 1) & 0x7e) | (data[8] >> 7));
-		input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f);
-		input_report_key(input, BTN_STYLUS, data[1] & 2);
-		input_report_key(input, BTN_STYLUS2, data[1] & 4);
-		input_report_key(input, BTN_TOUCH, t > 10);
-	}
-
-	/* airbrush second packet */
-	if ((data[1] & 0xbc) == 0xb4) {
-		input_report_abs(input, ABS_WHEEL,
-				(data[6] << 2) | ((data[7] >> 6) & 3));
-		input_report_abs(input, ABS_TILT_X,
-				((data[7] << 1) & 0x7e) | (data[8] >> 7));
-		input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f);
-	}
-}
-
-static int wacom_intuos_irq(struct wacom_wac *wacom)
-{
-	struct wacom_features *features = &wacom->features;
-	unsigned char *data = wacom->data;
-	struct input_dev *input = wacom->input;
-	unsigned int t;
-	int idx = 0, result;
-
-	if (data[0] != WACOM_REPORT_PENABLED &&
-	    data[0] != WACOM_REPORT_INTUOSREAD &&
-	    data[0] != WACOM_REPORT_INTUOSWRITE &&
-	    data[0] != WACOM_REPORT_INTUOSPAD &&
-	    data[0] != WACOM_REPORT_INTUOS5PAD) {
-		dev_dbg(input->dev.parent,
-			"%s: received unknown report #%d\n", __func__, data[0]);
-                return 0;
-	}
-
-	/* tool number */
-	if (features->type == INTUOS)
-		idx = data[1] & 0x01;
-
-	/* pad packets. Works as a second tool and is always in prox */
-	if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) {
-		input = wacom->pad_input;
-		if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
-			input_report_key(input, BTN_0, (data[2] & 0x01));
-			input_report_key(input, BTN_1, (data[3] & 0x01));
-			input_report_key(input, BTN_2, (data[3] & 0x02));
-			input_report_key(input, BTN_3, (data[3] & 0x04));
-			input_report_key(input, BTN_4, (data[3] & 0x08));
-			input_report_key(input, BTN_5, (data[3] & 0x10));
-			input_report_key(input, BTN_6, (data[3] & 0x20));
-			if (data[1] & 0x80) {
-				input_report_abs(input, ABS_WHEEL, (data[1] & 0x7f));
-			} else {
-				/* Out of proximity, clear wheel value. */
-				input_report_abs(input, ABS_WHEEL, 0);
-			}
-			if (features->type != INTUOS4S) {
-				input_report_key(input, BTN_7, (data[3] & 0x40));
-				input_report_key(input, BTN_8, (data[3] & 0x80));
-			}
-			if (data[1] | (data[2] & 0x01) | data[3]) {
-				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-			} else {
-				input_report_abs(input, ABS_MISC, 0);
-			}
-		} else if (features->type == DTK) {
-			input_report_key(input, BTN_0, (data[6] & 0x01));
-			input_report_key(input, BTN_1, (data[6] & 0x02));
-			input_report_key(input, BTN_2, (data[6] & 0x04));
-			input_report_key(input, BTN_3, (data[6] & 0x08));
-			input_report_key(input, BTN_4, (data[6] & 0x10));
-			input_report_key(input, BTN_5, (data[6] & 0x20));
-			if (data[6] & 0x3f) {
-				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-			} else {
-				input_report_abs(input, ABS_MISC, 0);
-			}
-		} else if (features->type == WACOM_13HD) {
-			input_report_key(input, BTN_0, (data[3] & 0x01));
-			input_report_key(input, BTN_1, (data[4] & 0x01));
-			input_report_key(input, BTN_2, (data[4] & 0x02));
-			input_report_key(input, BTN_3, (data[4] & 0x04));
-			input_report_key(input, BTN_4, (data[4] & 0x08));
-			input_report_key(input, BTN_5, (data[4] & 0x10));
-			input_report_key(input, BTN_6, (data[4] & 0x20));
-			input_report_key(input, BTN_7, (data[4] & 0x40));
-			input_report_key(input, BTN_8, (data[4] & 0x80));
-			if ((data[3] & 0x01) | data[4]) {
-				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-			} else {
-				input_report_abs(input, ABS_MISC, 0);
-			}
-		} else if (features->type == WACOM_24HD) {
-			input_report_key(input, BTN_0, (data[6] & 0x01));
-			input_report_key(input, BTN_1, (data[6] & 0x02));
-			input_report_key(input, BTN_2, (data[6] & 0x04));
-			input_report_key(input, BTN_3, (data[6] & 0x08));
-			input_report_key(input, BTN_4, (data[6] & 0x10));
-			input_report_key(input, BTN_5, (data[6] & 0x20));
-			input_report_key(input, BTN_6, (data[6] & 0x40));
-			input_report_key(input, BTN_7, (data[6] & 0x80));
-			input_report_key(input, BTN_8, (data[8] & 0x01));
-			input_report_key(input, BTN_9, (data[8] & 0x02));
-			input_report_key(input, BTN_A, (data[8] & 0x04));
-			input_report_key(input, BTN_B, (data[8] & 0x08));
-			input_report_key(input, BTN_C, (data[8] & 0x10));
-			input_report_key(input, BTN_X, (data[8] & 0x20));
-			input_report_key(input, BTN_Y, (data[8] & 0x40));
-			input_report_key(input, BTN_Z, (data[8] & 0x80));
-
-			/*
-			 * Three "buttons" are available on the 24HD which are
-			 * physically implemented as a touchstrip. Each button
-			 * is approximately 3 bits wide with a 2 bit spacing.
-			 * The raw touchstrip bits are stored at:
-			 *    ((data[3] & 0x1f) << 8) | data[4])
-			 */
-			input_report_key(input, KEY_PROG1, data[4] & 0x07);
-			input_report_key(input, KEY_PROG2, data[4] & 0xE0);
-			input_report_key(input, KEY_PROG3, data[3] & 0x1C);
-
-			if (data[1] & 0x80) {
-				input_report_abs(input, ABS_WHEEL, (data[1] & 0x7f));
-			} else {
-				/* Out of proximity, clear wheel value. */
-				input_report_abs(input, ABS_WHEEL, 0);
-			}
-
-			if (data[2] & 0x80) {
-				input_report_abs(input, ABS_THROTTLE, (data[2] & 0x7f));
-			} else {
-				/* Out of proximity, clear second wheel value. */
-				input_report_abs(input, ABS_THROTTLE, 0);
-			}
-
-			if (data[1] | data[2] | (data[3] & 0x1f) | data[4] | data[6] | data[8]) {
-				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-			} else {
-				input_report_abs(input, ABS_MISC, 0);
-			}
-		} else if (features->type == CINTIQ_HYBRID) {
-			/*
-			 * Do not send hardware buttons under Android. They
-			 * are already sent to the system through GPIO (and
-			 * have different meaning).
-			 */
-			input_report_key(input, BTN_1, (data[4] & 0x01));
-			input_report_key(input, BTN_2, (data[4] & 0x02));
-			input_report_key(input, BTN_3, (data[4] & 0x04));
-			input_report_key(input, BTN_4, (data[4] & 0x08));
-
-			input_report_key(input, BTN_5, (data[4] & 0x10));  /* Right  */
-			input_report_key(input, BTN_6, (data[4] & 0x20));  /* Up     */
-			input_report_key(input, BTN_7, (data[4] & 0x40));  /* Left   */
-			input_report_key(input, BTN_8, (data[4] & 0x80));  /* Down   */
-			input_report_key(input, BTN_0, (data[3] & 0x01));  /* Center */
-		} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
-			int i;
-
-			/* Touch ring mode switch has no capacitive sensor */
-			input_report_key(input, BTN_0, (data[3] & 0x01));
-
-			/*
-			 * ExpressKeys on Intuos5/Intuos Pro have a capacitive sensor in
-			 * addition to the mechanical switch. Switch data is
-			 * stored in data[4], capacitive data in data[5].
-			 */
-			for (i = 0; i < 8; i++)
-				input_report_key(input, BTN_1 + i, data[4] & (1 << i));
-
-			if (data[2] & 0x80) {
-				input_report_abs(input, ABS_WHEEL, (data[2] & 0x7f));
-			} else {
-				/* Out of proximity, clear wheel value. */
-				input_report_abs(input, ABS_WHEEL, 0);
-			}
-
-			if (data[2] | (data[3] & 0x01) | data[4] | data[5]) {
-				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-			} else {
-				input_report_abs(input, ABS_MISC, 0);
-			}
-		} else {
-			if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
-				input_report_key(input, BTN_0, (data[5] & 0x01));
-				input_report_key(input, BTN_1, (data[6] & 0x01));
-				input_report_key(input, BTN_2, (data[6] & 0x02));
-				input_report_key(input, BTN_3, (data[6] & 0x04));
-				input_report_key(input, BTN_4, (data[6] & 0x08));
-				input_report_key(input, BTN_5, (data[6] & 0x10));
-				input_report_key(input, BTN_6, (data[6] & 0x20));
-				input_report_key(input, BTN_7, (data[6] & 0x40));
-				input_report_key(input, BTN_8, (data[6] & 0x80));
-				input_report_key(input, BTN_9, (data[7] & 0x01));
-				input_report_key(input, BTN_A, (data[8] & 0x01));
-				input_report_key(input, BTN_B, (data[8] & 0x02));
-				input_report_key(input, BTN_C, (data[8] & 0x04));
-				input_report_key(input, BTN_X, (data[8] & 0x08));
-				input_report_key(input, BTN_Y, (data[8] & 0x10));
-				input_report_key(input, BTN_Z, (data[8] & 0x20));
-				input_report_key(input, BTN_BASE, (data[8] & 0x40));
-				input_report_key(input, BTN_BASE2, (data[8] & 0x80));
-
-				if (features->type == WACOM_22HD) {
-					input_report_key(input, KEY_PROG1, data[9] & 0x01);
-					input_report_key(input, KEY_PROG2, data[9] & 0x02);
-					input_report_key(input, KEY_PROG3, data[9] & 0x04);
-				}
-			} else {
-				input_report_key(input, BTN_0, (data[5] & 0x01));
-				input_report_key(input, BTN_1, (data[5] & 0x02));
-				input_report_key(input, BTN_2, (data[5] & 0x04));
-				input_report_key(input, BTN_3, (data[5] & 0x08));
-				input_report_key(input, BTN_4, (data[6] & 0x01));
-				input_report_key(input, BTN_5, (data[6] & 0x02));
-				input_report_key(input, BTN_6, (data[6] & 0x04));
-				input_report_key(input, BTN_7, (data[6] & 0x08));
-				input_report_key(input, BTN_8, (data[5] & 0x10));
-				input_report_key(input, BTN_9, (data[6] & 0x10));
-			}
-			input_report_abs(input, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
-			input_report_abs(input, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
-
-			if ((data[5] & 0x1f) | data[6] | (data[1] & 0x1f) |
-				data[2] | (data[3] & 0x1f) | data[4] | data[8] |
-				(data[7] & 0x01)) {
-				input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-			} else {
-				input_report_abs(input, ABS_MISC, 0);
-			}
-		}
-                return 1;
-	}
-
-	/* process in/out prox events */
-	result = wacom_intuos_inout(wacom);
-	if (result)
-                return result - 1;
-
-	/* don't proceed if we don't know the ID */
-	if (!wacom->id[idx])
-		return 0;
-
-	/* Only large Intuos support Lense Cursor */
-	if (wacom->tool[idx] == BTN_TOOL_LENS &&
-	    (features->type == INTUOS3 ||
-	     features->type == INTUOS3S ||
-	     features->type == INTUOS4 ||
-	     features->type == INTUOS4S ||
-	     features->type == INTUOS5 ||
-	     features->type == INTUOS5S ||
-	     features->type == INTUOSPM ||
-	     features->type == INTUOSPS)) {
-
-		return 0;
-	}
-
-	/* Cintiq doesn't send data when RDY bit isn't set */
-	if (features->type == CINTIQ && !(data[1] & 0x40))
-                 return 0;
-
-	if (features->type >= INTUOS3S) {
-		input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
-		input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
-		input_report_abs(input, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
-	} else {
-		input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[2]));
-		input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[4]));
-		input_report_abs(input, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
-	}
-
-	/* process general packets */
-	wacom_intuos_general(wacom);
-
-	/* 4D mouse, 2D mouse, marker pen rotation, tilt mouse, or Lens cursor packets */
-	if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0 || (data[1] & 0xbc) == 0xac) {
-
-		if (data[1] & 0x02) {
-			/* Rotation packet */
-			if (features->type >= INTUOS3S) {
-				/* I3 marker pen rotation */
-				t = (data[6] << 3) | ((data[7] >> 5) & 7);
-				t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
-					((t-1) / 2 + 450)) : (450 - t / 2) ;
-				input_report_abs(input, ABS_Z, t);
-			} else {
-				/* 4D mouse rotation packet */
-				t = (data[6] << 3) | ((data[7] >> 5) & 7);
-				input_report_abs(input, ABS_RZ, (data[7] & 0x20) ?
-					((t - 1) / 2) : -t / 2);
-			}
-
-		} else if (!(data[1] & 0x10) && features->type < INTUOS3S) {
-			/* 4D mouse packet */
-			input_report_key(input, BTN_LEFT,   data[8] & 0x01);
-			input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
-			input_report_key(input, BTN_RIGHT,  data[8] & 0x04);
-
-			input_report_key(input, BTN_SIDE,   data[8] & 0x20);
-			input_report_key(input, BTN_EXTRA,  data[8] & 0x10);
-			t = (data[6] << 2) | ((data[7] >> 6) & 3);
-			input_report_abs(input, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
-
-		} else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
-			/* I4 mouse */
-			if (features->type >= INTUOS4S && features->type <= INTUOSPL) {
-				input_report_key(input, BTN_LEFT,   data[6] & 0x01);
-				input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
-				input_report_key(input, BTN_RIGHT,  data[6] & 0x04);
-				input_report_rel(input, REL_WHEEL, ((data[7] & 0x80) >> 7)
-						 - ((data[7] & 0x40) >> 6));
-				input_report_key(input, BTN_SIDE,   data[6] & 0x08);
-				input_report_key(input, BTN_EXTRA,  data[6] & 0x10);
-
-				input_report_abs(input, ABS_TILT_X,
-					((data[7] << 1) & 0x7e) | (data[8] >> 7));
-				input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f);
-			} else {
-				/* 2D mouse packet */
-				input_report_key(input, BTN_LEFT,   data[8] & 0x04);
-				input_report_key(input, BTN_MIDDLE, data[8] & 0x08);
-				input_report_key(input, BTN_RIGHT,  data[8] & 0x10);
-				input_report_rel(input, REL_WHEEL, (data[8] & 0x01)
-						 - ((data[8] & 0x02) >> 1));
-
-				/* I3 2D mouse side buttons */
-				if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
-					input_report_key(input, BTN_SIDE,   data[8] & 0x40);
-					input_report_key(input, BTN_EXTRA,  data[8] & 0x20);
-				}
-			}
-		} else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
-				features->type == INTUOS4L || features->type == INTUOS5L ||
-				features->type == INTUOSPL) &&
-			   wacom->tool[idx] == BTN_TOOL_LENS) {
-			/* Lens cursor packets */
-			input_report_key(input, BTN_LEFT,   data[8] & 0x01);
-			input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
-			input_report_key(input, BTN_RIGHT,  data[8] & 0x04);
-			input_report_key(input, BTN_SIDE,   data[8] & 0x10);
-			input_report_key(input, BTN_EXTRA,  data[8] & 0x08);
-		}
-	}
-
-	input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */
-	input_report_key(input, wacom->tool[idx], 1);
-	input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
-	return 1;
-}
-
-static int int_dist(int x1, int y1, int x2, int y2)
-{
-	int x = x2 - x1;
-	int y = y2 - y1;
-
-	return int_sqrt(x*x + y*y);
-}
-
-static int wacom_24hdt_irq(struct wacom_wac *wacom)
-{
-	struct input_dev *input = wacom->input;
-	unsigned char *data = wacom->data;
-	int i;
-	int current_num_contacts = data[61];
-	int contacts_to_send = 0;
-
-	/*
-	 * First packet resets the counter since only the first
-	 * packet in series will have non-zero current_num_contacts.
-	 */
-	if (current_num_contacts)
-		wacom->num_contacts_left = current_num_contacts;
-
-	/* There are at most 4 contacts per packet */
-	contacts_to_send = min(4, wacom->num_contacts_left);
-
-	for (i = 0; i < contacts_to_send; i++) {
-		int offset = (WACOM_BYTES_PER_24HDT_PACKET * i) + 1;
-		bool touch = data[offset] & 0x1 && !wacom->shared->stylus_in_proximity;
-		int slot = input_mt_get_slot_by_key(input, data[offset + 1]);
-
-		if (slot < 0)
-			continue;
-		input_mt_slot(input, slot);
-		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
-
-		if (touch) {
-			int t_x = get_unaligned_le16(&data[offset + 2]);
-			int c_x = get_unaligned_le16(&data[offset + 4]);
-			int t_y = get_unaligned_le16(&data[offset + 6]);
-			int c_y = get_unaligned_le16(&data[offset + 8]);
-			int w = get_unaligned_le16(&data[offset + 10]);
-			int h = get_unaligned_le16(&data[offset + 12]);
-
-			input_report_abs(input, ABS_MT_POSITION_X, t_x);
-			input_report_abs(input, ABS_MT_POSITION_Y, t_y);
-			input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h));
-			input_report_abs(input, ABS_MT_WIDTH_MAJOR, min(w, h) + int_dist(t_x, t_y, c_x, c_y));
-			input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
-			input_report_abs(input, ABS_MT_ORIENTATION, w > h);
-		}
-	}
-	input_mt_report_pointer_emulation(input, true);
-
-	wacom->num_contacts_left -= contacts_to_send;
-	if (wacom->num_contacts_left <= 0)
-		wacom->num_contacts_left = 0;
-
-	return 1;
-}
-
-static int wacom_mt_touch(struct wacom_wac *wacom)
-{
-	struct input_dev *input = wacom->input;
-	unsigned char *data = wacom->data;
-	int i;
-	int current_num_contacts = data[2];
-	int contacts_to_send = 0;
-	int x_offset = 0;
-
-	/* MTTPC does not support Height and Width */
-	if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
-		x_offset = -4;
-
-	/*
-	 * First packet resets the counter since only the first
-	 * packet in series will have non-zero current_num_contacts.
-	 */
-	if (current_num_contacts)
-		wacom->num_contacts_left = current_num_contacts;
-
-	/* There are at most 5 contacts per packet */
-	contacts_to_send = min(5, wacom->num_contacts_left);
-
-	for (i = 0; i < contacts_to_send; i++) {
-		int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
-		bool touch = data[offset] & 0x1;
-		int id = get_unaligned_le16(&data[offset + 1]);
-		int slot = input_mt_get_slot_by_key(input, id);
-
-		if (slot < 0)
-			continue;
-
-		input_mt_slot(input, slot);
-		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
-		if (touch) {
-			int x = get_unaligned_le16(&data[offset + x_offset + 7]);
-			int y = get_unaligned_le16(&data[offset + x_offset + 9]);
-			input_report_abs(input, ABS_MT_POSITION_X, x);
-			input_report_abs(input, ABS_MT_POSITION_Y, y);
-		}
-	}
-	input_mt_report_pointer_emulation(input, true);
-
-	wacom->num_contacts_left -= contacts_to_send;
-	if (wacom->num_contacts_left < 0)
-		wacom->num_contacts_left = 0;
-
-	return 1;
-}
-
-static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
-{
-	struct input_dev *input = wacom->input;
-	unsigned char *data = wacom->data;
-	int contact_with_no_pen_down_count = 0;
-	int i;
-
-	for (i = 0; i < 2; i++) {
-		int p = data[1] & (1 << i);
-		bool touch = p && !wacom->shared->stylus_in_proximity;
-
-		input_mt_slot(input, i);
-		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
-		if (touch) {
-			int x = le16_to_cpup((__le16 *)&data[i * 2 + 2]) & 0x7fff;
-			int y = le16_to_cpup((__le16 *)&data[i * 2 + 6]) & 0x7fff;
-
-			input_report_abs(input, ABS_MT_POSITION_X, x);
-			input_report_abs(input, ABS_MT_POSITION_Y, y);
-			contact_with_no_pen_down_count++;
-		}
-	}
-	input_mt_report_pointer_emulation(input, true);
-
-	/* keep touch state for pen event */
-	wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
-
-	return 1;
-}
-
-static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
-{
-	unsigned char *data = wacom->data;
-	struct input_dev *input = wacom->input;
-	bool prox;
-	int x = 0, y = 0;
-
-	if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
-		return 0;
-
-	if (!wacom->shared->stylus_in_proximity) {
-		if (len == WACOM_PKGLEN_TPC1FG) {
-			prox = data[0] & 0x01;
-			x = get_unaligned_le16(&data[1]);
-			y = get_unaligned_le16(&data[3]);
-		} else if (len == WACOM_PKGLEN_TPC1FG_B) {
-			prox = data[2] & 0x01;
-			x = get_unaligned_le16(&data[3]);
-			y = get_unaligned_le16(&data[5]);
-		} else {
-			prox = data[1] & 0x01;
-			x = le16_to_cpup((__le16 *)&data[2]);
-			y = le16_to_cpup((__le16 *)&data[4]);
-		}
-	} else
-		/* force touch out when pen is in prox */
-		prox = 0;
-
-	if (prox) {
-		input_report_abs(input, ABS_X, x);
-		input_report_abs(input, ABS_Y, y);
-	}
-	input_report_key(input, BTN_TOUCH, prox);
-
-	/* keep touch state for pen events */
-	wacom->shared->touch_down = prox;
-
-	return 1;
-}
-
-static int wacom_tpc_pen(struct wacom_wac *wacom)
-{
-	unsigned char *data = wacom->data;
-	struct input_dev *input = wacom->input;
-	bool prox = data[1] & 0x20;
-
-	if (!wacom->shared->stylus_in_proximity) /* first in prox */
-		/* Going into proximity select tool */
-		wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
-
-	/* keep pen state for touch events */
-	wacom->shared->stylus_in_proximity = prox;
-
-	/* send pen events only when touch is up or forced out */
-	if (!wacom->shared->touch_down) {
-		input_report_key(input, BTN_STYLUS, data[1] & 0x02);
-		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_key(input, BTN_TOUCH, data[1] & 0x05);
-		input_report_key(input, wacom->tool[0], prox);
-		return 1;
-	}
-
-	return 0;
-}
-
-static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
-{
-	unsigned char *data = wacom->data;
-
-	dev_dbg(wacom->input->dev.parent,
-		"%s: received report #%d\n", __func__, data[0]);
-
-	switch (len) {
-	case WACOM_PKGLEN_TPC1FG:
-		return wacom_tpc_single_touch(wacom, len);
-
-	case WACOM_PKGLEN_TPC2FG:
-		return wacom_tpc_mt_touch(wacom);
-
-	case WACOM_PKGLEN_PENABLED:
-		return wacom_tpc_pen(wacom);
-
-	default:
-		switch (data[0]) {
-		case WACOM_REPORT_TPC1FG:
-		case WACOM_REPORT_TPCHID:
-		case WACOM_REPORT_TPCST:
-		case WACOM_REPORT_TPC1FGE:
-			return wacom_tpc_single_touch(wacom, len);
-
-		case WACOM_REPORT_TPCMT:
-		case WACOM_REPORT_TPCMT2:
-			return wacom_mt_touch(wacom);
-
-		case WACOM_REPORT_PENABLED:
-			return wacom_tpc_pen(wacom);
-		}
-	}
-
-	return 0;
-}
-
-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;
-
-	if (data[0] != 0x02)
-	    return 0;
-
-	for (i = 0; i < 2; i++) {
-		int offset = (data[1] & 0x80) ? (8 * i) : (9 * i);
-		bool touch = data[offset + 3] & 0x80;
-
-		/*
-		 * Touch events need to be disabled while stylus is
-		 * in proximity because user's hand is resting on touchpad
-		 * and sending unwanted events.  User expects tablet buttons
-		 * to continue working though.
-		 */
-		touch = touch && !wacom->shared->stylus_in_proximity;
-
-		input_mt_slot(input, i);
-		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
-		if (touch) {
-			int x = get_unaligned_be16(&data[offset + 3]) & 0x7ff;
-			int y = get_unaligned_be16(&data[offset + 5]) & 0x7ff;
-			if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
-				x <<= 5;
-				y <<= 5;
-			}
-			input_report_abs(input, ABS_MT_POSITION_X, x);
-			input_report_abs(input, ABS_MT_POSITION_Y, y);
-		}
-	}
-
-	input_mt_report_pointer_emulation(input, true);
-
-	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 1;
-}
-
-static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
-{
-	struct wacom_features *features = &wacom->features;
-	struct input_dev *input = wacom->input;
-	bool touch = data[1] & 0x80;
-	int slot = input_mt_get_slot_by_key(input, data[0]);
-
-	if (slot < 0)
-		return;
-
-	touch = touch && !wacom->shared->stylus_in_proximity;
-
-	input_mt_slot(input, slot);
-	input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
-
-	if (touch) {
-		int x = (data[2] << 4) | (data[4] >> 4);
-		int y = (data[3] << 4) | (data[4] & 0x0f);
-		int width, height;
-
-		if (features->type >= INTUOSPS && features->type <= INTUOSPL) {
-			width  = data[5] * 100;
-			height = data[6] * 100;
-		} else {
-			/*
-			 * "a" is a scaled-down area which we assume is
-			 * roughly circular and which can be described as:
-			 * a=(pi*r^2)/C.
-			 */
-			int a = data[5];
-			int x_res = input_abs_get_res(input, ABS_MT_POSITION_X);
-			int y_res = input_abs_get_res(input, ABS_MT_POSITION_Y);
-			width = 2 * int_sqrt(a * WACOM_CONTACT_AREA_SCALE);
-			height = width * y_res / x_res;
-		}
-
-		input_report_abs(input, ABS_MT_POSITION_X, x);
-		input_report_abs(input, ABS_MT_POSITION_Y, y);
-		input_report_abs(input, ABS_MT_TOUCH_MAJOR, width);
-		input_report_abs(input, ABS_MT_TOUCH_MINOR, height);
-	}
-}
-
-static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
-{
-	struct input_dev *input = wacom->pad_input;
-	struct wacom_features *features = &wacom->features;
-
-	if (features->type == INTUOSHT) {
-		input_report_key(input, BTN_LEFT, (data[1] & 0x02) != 0);
-		input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0);
-	} else {
-		input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);
-		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_RIGHT, (data[1] & 0x01) != 0);
-}
-
-static int wacom_bpt3_touch(struct wacom_wac *wacom)
-{
-	struct input_dev *input = wacom->input;
-	unsigned char *data = wacom->data;
-	int count = data[1] & 0x07;
-	int i;
-
-	if (data[0] != 0x02)
-	    return 0;
-
-	/* data has up to 7 fixed sized 8-byte messages starting at data[2] */
-	for (i = 0; i < count; i++) {
-		int offset = (8 * i) + 2;
-		int msg_id = data[offset];
-
-		if (msg_id >= 2 && msg_id <= 17)
-			wacom_bpt3_touch_msg(wacom, data + offset);
-		else if (msg_id == 128)
-			wacom_bpt3_button_msg(wacom, data + offset);
-
-	}
-	input_mt_report_pointer_emulation(input, true);
-
-	return 1;
-}
-
-static int wacom_bpt_pen(struct wacom_wac *wacom)
-{
-	struct wacom_features *features = &wacom->features;
-	struct input_dev *input = wacom->input;
-	unsigned char *data = wacom->data;
-	int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0;
-
-	if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_USB)
-	    return 0;
-
-	if (data[0] == WACOM_REPORT_USB) {
-		if (features->type == INTUOSHT && features->touch_max) {
-			input_report_switch(wacom->shared->touch_input,
-					    SW_MUTE_DEVICE, data[8] & 0x40);
-			input_sync(wacom->shared->touch_input);
-		}
-		return 0;
-	}
-
-	prox = (data[1] & 0x20) == 0x20;
-
-	/*
-	 * All reports shared between PEN and RUBBER tool must be
-	 * forced to a known starting value (zero) when transitioning to
-	 * out-of-prox.
-	 *
-	 * If not reset then, to userspace, it will look like lost events
-	 * if new tool comes in-prox with same values as previous tool sent.
-	 *
-	 * Hardware does report zero in most out-of-prox cases but not all.
-	 */
-	if (prox) {
-		if (!wacom->shared->stylus_in_proximity) {
-			if (data[1] & 0x08) {
-				wacom->tool[0] = BTN_TOOL_RUBBER;
-				wacom->id[0] = ERASER_DEVICE_ID;
-			} else {
-				wacom->tool[0] = BTN_TOOL_PEN;
-				wacom->id[0] = STYLUS_DEVICE_ID;
-			}
-			wacom->shared->stylus_in_proximity = true;
-		}
-		x = le16_to_cpup((__le16 *)&data[2]);
-		y = le16_to_cpup((__le16 *)&data[4]);
-		p = le16_to_cpup((__le16 *)&data[6]);
-		/*
-		 * Convert distance from out prox to distance from tablet.
-		 * distance will be greater than distance_max once
-		 * touching and applying pressure; do not report negative
-		 * distance.
-		 */
-		if (data[8] <= features->distance_max)
-			d = features->distance_max - data[8];
-
-		pen = data[1] & 0x01;
-		btn1 = data[1] & 0x02;
-		btn2 = data[1] & 0x04;
-	}
-
-	input_report_key(input, BTN_TOUCH, pen);
-	input_report_key(input, BTN_STYLUS, btn1);
-	input_report_key(input, BTN_STYLUS2, btn2);
-
-	input_report_abs(input, ABS_X, x);
-	input_report_abs(input, ABS_Y, y);
-	input_report_abs(input, ABS_PRESSURE, p);
-	input_report_abs(input, ABS_DISTANCE, d);
-
-	if (!prox) {
-		wacom->id[0] = 0;
-		wacom->shared->stylus_in_proximity = false;
-	}
-
-	input_report_key(input, wacom->tool[0], prox); /* PEN or RUBBER */
-	input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
-
-	return 1;
-}
-
-static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
-{
-	if (len == WACOM_PKGLEN_BBTOUCH)
-		return wacom_bpt_touch(wacom);
-	else if (len == WACOM_PKGLEN_BBTOUCH3)
-		return wacom_bpt3_touch(wacom);
-	else if (len == WACOM_PKGLEN_BBFUN || len == WACOM_PKGLEN_BBPEN)
-		return wacom_bpt_pen(wacom);
-
-	return 0;
-}
-
-static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
-{
-	unsigned char *data = wacom->data;
-	int connected;
-
-	if (len != WACOM_PKGLEN_WIRELESS || data[0] != WACOM_REPORT_WL)
-		return 0;
-
-	connected = data[1] & 0x01;
-	if (connected) {
-		int pid, battery;
-
-		if ((wacom->shared->type == INTUOSHT) &&
-				wacom->shared->touch_max) {
-			input_report_switch(wacom->shared->touch_input,
-					SW_MUTE_DEVICE, data[5] & 0x40);
-			input_sync(wacom->shared->touch_input);
-		}
-
-		pid = get_unaligned_be16(&data[6]);
-		battery = data[5] & 0x3f;
-		if (wacom->pid != pid) {
-			wacom->pid = pid;
-			wacom_schedule_work(wacom);
-		}
-		wacom->battery_capacity = battery;
-	} else if (wacom->pid != 0) {
-		/* disconnected while previously connected */
-		wacom->pid = 0;
-		wacom_schedule_work(wacom);
-		wacom->battery_capacity = 0;
-	}
-
-	return 0;
-}
-
-void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
-{
-	bool sync;
-
-	switch (wacom_wac->features.type) {
-	case PENPARTNER:
-		sync = wacom_penpartner_irq(wacom_wac);
-		break;
-
-	case PL:
-		sync = wacom_pl_irq(wacom_wac);
-		break;
-
-	case WACOM_G4:
-	case GRAPHIRE:
-	case WACOM_MO:
-		sync = wacom_graphire_irq(wacom_wac);
-		break;
-
-	case PTU:
-		sync = wacom_ptu_irq(wacom_wac);
-		break;
-
-	case DTU:
-		sync = wacom_dtu_irq(wacom_wac);
-		break;
-
-	case DTUS:
-		sync = wacom_dtus_irq(wacom_wac);
-		break;
-
-	case INTUOS:
-	case INTUOS3S:
-	case INTUOS3:
-	case INTUOS3L:
-	case INTUOS4S:
-	case INTUOS4:
-	case INTUOS4L:
-	case CINTIQ:
-	case WACOM_BEE:
-	case WACOM_13HD:
-	case WACOM_21UX2:
-	case WACOM_22HD:
-	case WACOM_24HD:
-	case DTK:
-	case CINTIQ_HYBRID:
-		sync = wacom_intuos_irq(wacom_wac);
-		break;
-
-	case WACOM_24HDT:
-		sync = wacom_24hdt_irq(wacom_wac);
-		break;
-
-	case INTUOS5S:
-	case INTUOS5:
-	case INTUOS5L:
-	case INTUOSPS:
-	case INTUOSPM:
-	case INTUOSPL:
-		if (len == WACOM_PKGLEN_BBTOUCH3)
-			sync = wacom_bpt3_touch(wacom_wac);
-		else
-			sync = wacom_intuos_irq(wacom_wac);
-		break;
-
-	case TABLETPC:
-	case TABLETPCE:
-	case TABLETPC2FG:
-	case MTSCREEN:
-	case MTTPC:
-	case MTTPC_B:
-		sync = wacom_tpc_irq(wacom_wac, len);
-		break;
-
-	case BAMBOO_PT:
-	case INTUOSHT:
-		sync = wacom_bpt_irq(wacom_wac, len);
-		break;
-
-	case WIRELESS:
-		sync = wacom_wireless_irq(wacom_wac, len);
-		break;
-
-	default:
-		sync = false;
-		break;
-	}
-
-	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)
-{
-	struct input_dev *input_dev = wacom_wac->input;
-
-	input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
-
-	__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
-	__set_bit(BTN_TOOL_PEN, input_dev->keybit);
-	__set_bit(BTN_TOOL_BRUSH, input_dev->keybit);
-	__set_bit(BTN_TOOL_PENCIL, input_dev->keybit);
-	__set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit);
-	__set_bit(BTN_STYLUS, input_dev->keybit);
-	__set_bit(BTN_STYLUS2, input_dev->keybit);
-
-	input_set_abs_params(input_dev, ABS_DISTANCE,
-			     0, wacom_wac->features.distance_max, 0, 0);
-	input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
-	input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
-	input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
-}
-
-static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
-{
-	struct input_dev *input_dev = wacom_wac->input;
-
-	input_set_capability(input_dev, EV_REL, REL_WHEEL);
-
-	wacom_setup_cintiq(wacom_wac);
-
-	__set_bit(BTN_LEFT, input_dev->keybit);
-	__set_bit(BTN_RIGHT, input_dev->keybit);
-	__set_bit(BTN_MIDDLE, input_dev->keybit);
-	__set_bit(BTN_SIDE, input_dev->keybit);
-	__set_bit(BTN_EXTRA, input_dev->keybit);
-	__set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
-	__set_bit(BTN_TOOL_LENS, input_dev->keybit);
-
-	input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
-	input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
-}
-
-void wacom_setup_device_quirks(struct wacom_features *features)
-{
-
-	/* touch device found but size is not defined. use default */
-	if (features->device_type == BTN_TOOL_FINGER && !features->x_max) {
-		features->x_max = 1023;
-		features->y_max = 1023;
-	}
-
-	/* these device have multiple inputs */
-	if (features->type >= WIRELESS ||
-	    (features->type >= INTUOS5S && features->type <= INTUOSHT) ||
-	    (features->oVid && features->oPid))
-		features->quirks |= WACOM_QUIRK_MULTI_INPUT;
-
-	/* quirk for bamboo touch with 2 low res touches */
-	if (features->type == BAMBOO_PT &&
-	    features->pktlen == WACOM_PKGLEN_BBTOUCH) {
-		features->x_max <<= 5;
-		features->y_max <<= 5;
-		features->x_fuzz <<= 5;
-		features->y_fuzz <<= 5;
-		features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES;
-	}
-
-	if (features->type == WIRELESS) {
-
-		/* monitor never has input and pen/touch have delayed create */
-		features->quirks |= WACOM_QUIRK_NO_INPUT;
-
-		/* must be monitor interface if no device_type set */
-		if (!features->device_type)
-			features->quirks |= WACOM_QUIRK_MONITOR;
-	}
-}
-
-static void wacom_abs_set_axis(struct input_dev *input_dev,
-			       struct wacom_wac *wacom_wac)
-{
-	struct wacom_features *features = &wacom_wac->features;
-
-	if (features->device_type == BTN_TOOL_PEN) {
-		input_set_abs_params(input_dev, ABS_X, features->x_min,
-				     features->x_max, features->x_fuzz, 0);
-		input_set_abs_params(input_dev, ABS_Y, features->y_min,
-				     features->y_max, features->y_fuzz, 0);
-		input_set_abs_params(input_dev, ABS_PRESSURE, 0,
-			features->pressure_max, features->pressure_fuzz, 0);
-
-		/* penabled devices have fixed resolution for each model */
-		input_abs_set_res(input_dev, ABS_X, features->x_resolution);
-		input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
-	} else {
-		if (features->touch_max == 1) {
-			input_set_abs_params(input_dev, ABS_X, 0,
-				features->x_max, features->x_fuzz, 0);
-			input_set_abs_params(input_dev, ABS_Y, 0,
-				features->y_max, features->y_fuzz, 0);
-			input_abs_set_res(input_dev, ABS_X,
-					  features->x_resolution);
-			input_abs_set_res(input_dev, ABS_Y,
-					  features->y_resolution);
-		}
-
-		if (features->touch_max > 1) {
-			input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
-				features->x_max, features->x_fuzz, 0);
-			input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
-				features->y_max, features->y_fuzz, 0);
-			input_abs_set_res(input_dev, ABS_MT_POSITION_X,
-					  features->x_resolution);
-			input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
-					  features->y_resolution);
-		}
-	}
-}
-
-int wacom_setup_input_capabilities(struct input_dev *input_dev,
-				   struct wacom_wac *wacom_wac)
-{
-	struct wacom_features *features = &wacom_wac->features;
-
-	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-
-	__set_bit(BTN_TOUCH, input_dev->keybit);
-	__set_bit(ABS_MISC, input_dev->absbit);
-
-	wacom_abs_set_axis(input_dev, wacom_wac);
-
-	switch (features->type) {
-	case WACOM_MO:
-		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
-		/* fall through */
-
-	case WACOM_G4:
-		/* fall through */
-
-	case GRAPHIRE:
-		input_set_capability(input_dev, EV_REL, REL_WHEEL);
-
-		__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:
-		__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
-
-		wacom_setup_cintiq(wacom_wac);
-		break;
-
-	case WACOM_22HD:
-	case WACOM_21UX2:
-	case WACOM_BEE:
-	case CINTIQ:
-		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;
-
-	case WACOM_13HD:
-		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;
-
-	case INTUOS3:
-	case INTUOS3L:
-	case INTUOS3S:
-		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
-		/* fall through */
-
-	case INTUOS:
-		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-
-		wacom_setup_intuos(wacom_wac);
-		break;
-
-	case INTUOS5:
-	case INTUOS5L:
-	case INTUOSPM:
-	case INTUOSPL:
-	case INTUOS5S:
-	case INTUOSPS:
-		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-
-		if (features->device_type == BTN_TOOL_PEN) {
-			input_set_abs_params(input_dev, ABS_DISTANCE, 0,
-					      features->distance_max,
-					      0, 0);
-
-			input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
-
-			wacom_setup_intuos(wacom_wac);
-		} else if (features->device_type == BTN_TOOL_FINGER) {
-			__clear_bit(ABS_MISC, input_dev->absbit);
-
-			input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
-			                     0, features->x_max, 0, 0);
-			input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
-			                     0, features->y_max, 0, 0);
-			input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
-		}
-		break;
-
-	case INTUOS4:
-	case INTUOS4L:
-	case INTUOS4S:
-		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
-		wacom_setup_intuos(wacom_wac);
-
-		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-		break;
-
-	case WACOM_24HDT:
-		if (features->device_type == BTN_TOOL_FINGER) {
-			input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0);
-			input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, features->x_max, 0, 0);
-			input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR, 0, features->y_max, 0, 0);
-			input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
-		}
-		/* fall through */
-
-	case MTSCREEN:
-	case MTTPC:
-	case MTTPC_B:
-	case TABLETPC2FG:
-		if (features->device_type == BTN_TOOL_FINGER && features->touch_max > 1)
-			input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_DIRECT);
-		/* fall through */
-
-	case TABLETPC:
-	case TABLETPCE:
-		__clear_bit(ABS_MISC, input_dev->absbit);
-
-		__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
-
-		if (features->device_type != BTN_TOOL_PEN)
-			break;  /* no need to process stylus stuff */
-
-		/* fall through */
-
-	case DTUS:
-	case PL:
-	case DTU:
-		__set_bit(BTN_TOOL_PEN, input_dev->keybit);
-		__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
-		__set_bit(BTN_STYLUS, input_dev->keybit);
-		__set_bit(BTN_STYLUS2, input_dev->keybit);
-
-		__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
-		break;
-
-	case PTU:
-		__set_bit(BTN_STYLUS2, input_dev->keybit);
-		/* fall through */
-
-	case PENPARTNER:
-		__set_bit(BTN_TOOL_PEN, input_dev->keybit);
-		__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
-		__set_bit(BTN_STYLUS, input_dev->keybit);
-
-		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-		break;
-
-	case INTUOSHT:
-		if (features->touch_max &&
-		    features->device_type == BTN_TOOL_FINGER) {
-			input_dev->evbit[0] |= BIT_MASK(EV_SW);
-			__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
-		}
-		/* fall through */
-
-	case BAMBOO_PT:
-		__clear_bit(ABS_MISC, input_dev->absbit);
-
-		if (features->device_type == BTN_TOOL_FINGER) {
-
-			if (features->touch_max) {
-				if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
-					input_set_abs_params(input_dev,
-						     ABS_MT_TOUCH_MAJOR,
-						     0, features->x_max, 0, 0);
-					input_set_abs_params(input_dev,
-						     ABS_MT_TOUCH_MINOR,
-						     0, features->y_max, 0, 0);
-				}
-				input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
-			} else {
-				/* buttons/keys only interface */
-				__clear_bit(ABS_X, input_dev->absbit);
-				__clear_bit(ABS_Y, input_dev->absbit);
-				__clear_bit(BTN_TOUCH, input_dev->keybit);
-			}
-		} else if (features->device_type == BTN_TOOL_PEN) {
-			__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-			__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
-			__set_bit(BTN_TOOL_PEN, input_dev->keybit);
-			__set_bit(BTN_STYLUS, input_dev->keybit);
-			__set_bit(BTN_STYLUS2, input_dev->keybit);
-			input_set_abs_params(input_dev, ABS_DISTANCE, 0,
-					      features->distance_max,
-					      0, 0);
-		}
-		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 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);
-
-		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);
-		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 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);
-
-		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", 5040, 3780, 255, 0,
-	  PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
-static const struct wacom_features wacom_features_0x10 =
-	{ "Wacom Graphire", 10206, 7422, 511, 63,
-	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
-static const struct wacom_features wacom_features_0x11 =
-	{ "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", 13918, 10206, 511, 63,
-	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
-static const struct wacom_features wacom_features_0x13 =
-	{ "Wacom Graphire3", 10208, 7424, 511, 63,
-	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
-static const struct wacom_features wacom_features_0x14 =
-	{ "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", 10208, 7424, 511, 63,
-	  WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
-static const struct wacom_features wacom_features_0x16 =
-	{ "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", 14760, 9225, 511, 63,
-	  WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x18 =
-	{ "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", 16704, 12064, 511, 63,
-	  GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
-static const struct wacom_features wacom_features_0x60 =
-	{ "Wacom Volito", 5104, 3712, 511, 63,
-	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
-static const struct wacom_features wacom_features_0x61 =
-	{ "Wacom PenStation2", 3250, 2320, 255, 63,
-	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
-static const struct wacom_features wacom_features_0x62 =
-	{ "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", 3248, 2320, 511, 63,
-	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
-static const struct wacom_features wacom_features_0x64 =
-	{ "Wacom PenPartner2", 3250, 2320, 511, 63,
-	  GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
-static const struct wacom_features wacom_features_0x65 =
-	{ "Wacom Bamboo", 14760, 9225, 511, 63,
-	  WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x69 =
-	{ "Wacom Bamboo1", 5104, 3712, 511, 63,
-	  GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
-static const struct wacom_features wacom_features_0x6A =
-	{ "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", 21648, 13530, 1023, 63,
-	  GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x20 =
-	{ "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", 20320, 16240, 1023, 31,
-	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x22 =
-	{ "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", 30480, 31680, 1023, 31,
-	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x24 =
-	{ "Wacom Intuos 12x18", 45720, 31680, 1023, 31,
-	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x30 =
-	{ "Wacom PL400", 5408, 4056, 255, 0,
-	  PL, WACOM_PL_RES, WACOM_PL_RES };
-static const struct wacom_features wacom_features_0x31 =
-	{ "Wacom PL500", 6144, 4608, 255, 0,
-	  PL, WACOM_PL_RES, WACOM_PL_RES };
-static const struct wacom_features wacom_features_0x32 =
-	{ "Wacom PL600", 6126, 4604, 255, 0,
-	  PL, WACOM_PL_RES, WACOM_PL_RES };
-static const struct wacom_features wacom_features_0x33 =
-	{ "Wacom PL600SX", 6260, 5016, 255, 0,
-	  PL, WACOM_PL_RES, WACOM_PL_RES };
-static const struct wacom_features wacom_features_0x34 =
-	{ "Wacom PL550", 6144, 4608, 511, 0,
-	  PL, WACOM_PL_RES, WACOM_PL_RES };
-static const struct wacom_features wacom_features_0x35 =
-	{ "Wacom PL800", 7220, 5780, 511, 0,
-	  PL, WACOM_PL_RES, WACOM_PL_RES };
-static const struct wacom_features wacom_features_0x37 =
-	{ "Wacom PL700", 6758, 5406, 511, 0,
-	  PL, WACOM_PL_RES, WACOM_PL_RES };
-static const struct wacom_features wacom_features_0x38 =
-	{ "Wacom PL510", 6282, 4762, 511, 0,
-	  PL, WACOM_PL_RES, WACOM_PL_RES };
-static const struct wacom_features wacom_features_0x39 =
-	{ "Wacom DTU710", 34080, 27660, 511, 0,
-	  PL, WACOM_PL_RES, WACOM_PL_RES };
-static const struct wacom_features wacom_features_0xC4 =
-	{ "Wacom DTF521", 6282, 4762, 511, 0,
-	  PL, WACOM_PL_RES, WACOM_PL_RES };
-static const struct wacom_features wacom_features_0xC0 =
-	{ "Wacom DTF720", 6858, 5506, 511, 0,
-	  PL, WACOM_PL_RES, WACOM_PL_RES };
-static const struct wacom_features wacom_features_0xC2 =
-	{ "Wacom DTF720a", 6858, 5506, 511, 0,
-	  PL, WACOM_PL_RES, WACOM_PL_RES };
-static const struct wacom_features wacom_features_0x03 =
-	{ "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", 12700, 10600, 1023, 31,
-	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x42 =
-	{ "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", 30480, 24060, 1023, 31,
-	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x44 =
-	{ "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", 45720, 31680, 1023, 31,
-	  INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0xB0 =
-	{ "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", 40640, 30480, 1023, 63,
-	  INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
-static const struct wacom_features wacom_features_0xB2 =
-	{ "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", 60960, 60960, 1023, 63,
-	  INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
-static const struct wacom_features wacom_features_0xB4 =
-	{ "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", 54204, 31750, 1023, 63,
-	  INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
-static const struct wacom_features wacom_features_0xB7 =
-	{ "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", 31496, 19685, 2047, 63,
-	  INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
-static const struct wacom_features wacom_features_0xB9 =
-	{ "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", 65024, 40640, 2047, 63,
-	  INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
-static const struct wacom_features wacom_features_0xBB =
-	{ "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", 40640, 25400, 2047, 63,
-	  INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
-static const struct wacom_features wacom_features_0x26 =
-	{ "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", 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", 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", 31496, 19685, 2047, 63,
-	  INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
-static const struct wacom_features wacom_features_0x2A =
-	{ "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", 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", 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", 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", 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", 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,
-	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
-static const struct wacom_features wacom_features_0x3F =
-	{ "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", 86680, 54180, 1023, 63,
-	  WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
-static const struct wacom_features wacom_features_0xC6 =
-	{ "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", 59352, 33648, 1023, 63,
-	  WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
-static const struct wacom_features wacom_features_0xC7 =
-	{ "Wacom DTU1931", 37832, 30305, 511, 0,
-	  PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0xCE =
-	{ "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", 34623, 19553, 511, 0,
-	  DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0xFB =
-	{ "Wacom DTU1031", 22096, 13960, 511, 0,
-	  DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x57 =
-	{ "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", 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,
-	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
-static const struct wacom_features wacom_features_0xCC =
-	{ "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", 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", 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,
-	  .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
-static const struct wacom_features wacom_features_0x90 =
-	{ "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", 26202, 16325, 255, 0,
-	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x97 =
-	{ "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", 26202, 16325, 255, 0,
-	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x9F =
-	{ "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", 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", 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", 26202, 16325, 255, 0,
-	  MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0xE6 =
-	{ "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", 25710, 14500, 255, 0,
-	  TABLETPC,    WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0xED =
-	{ "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", 26202, 16325, 255, 0,
-	  TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x100 =
-	{ "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", 26202, 16325, 255, 0,
-	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x10D =
-	{ "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", 27760, 15694, 255, 0,
-	  MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x10F =
-	{ "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", 26202, 16325, 255, 0,
-	  TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x4001 =
-	{ "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", 11060, 6220, 255, 0,
-	  MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x5000 =
-	{ "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", 29576, 16724, 1023, 0,
-	  MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x47 =
-	{ "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", 0, 0, 0, 0,
-	  WIRELESS, 0, 0, .touch_max = 16 };
-static const struct wacom_features wacom_features_0xD0 =
-	{ "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", 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", 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", 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", 14720, 9200, 1023, 31,
-	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0xD5 =
-	{ "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", 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", 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", 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", 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", 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", 14720, 9200, 1023, 31,
-          BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0xDE =
-        { "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", 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", 14720, 9225, 1023, 31,
-	  BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
-static const struct wacom_features wacom_features_0x301 =
-	{ "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", 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", 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", 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", 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_0x309 =
-	{ "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */
-	  .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)						\
-	HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
-	.driver_data = (kernel_ulong_t)&wacom_features_##prod
-
-#define USB_DEVICE_LENOVO(prod)					\
-	HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, prod),			\
-	.driver_data = (kernel_ulong_t)&wacom_features_##prod
-
-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) },
-	{ USB_DEVICE_WACOM(0x13) },
-	{ USB_DEVICE_WACOM(0x14) },
-	{ USB_DEVICE_WACOM(0x15) },
-	{ USB_DEVICE_WACOM(0x16) },
-	{ USB_DEVICE_WACOM(0x17) },
-	{ USB_DEVICE_WACOM(0x18) },
-	{ USB_DEVICE_WACOM(0x19) },
-	{ 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) },
-	{ USB_DEVICE_WACOM(0x33) },
-	{ USB_DEVICE_WACOM(0x34) },
-	{ USB_DEVICE_WACOM(0x35) },
-	{ USB_DEVICE_WACOM(0x37) },
-	{ USB_DEVICE_WACOM(0x38) },
-	{ USB_DEVICE_WACOM(0x39) },
-	{ 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_WACOM(0x5B) },
-	{ 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) },
-	{ 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) },
-	{ USB_DEVICE_WACOM(0xB3) },
-	{ USB_DEVICE_WACOM(0xB4) },
-	{ USB_DEVICE_WACOM(0xB5) },
-	{ USB_DEVICE_WACOM(0xB7) },
-	{ USB_DEVICE_WACOM(0xB8) },
-	{ USB_DEVICE_WACOM(0xB9) },
-	{ USB_DEVICE_WACOM(0xBA) },
-	{ USB_DEVICE_WACOM(0xBB) },
-	{ USB_DEVICE_WACOM(0xBC) },
-	{ USB_DEVICE_WACOM(0xC0) },
-	{ USB_DEVICE_WACOM(0xC2) },
-	{ USB_DEVICE_WACOM(0xC4) },
-	{ USB_DEVICE_WACOM(0xC5) },
-	{ USB_DEVICE_WACOM(0xC6) },
-	{ USB_DEVICE_WACOM(0xC7) },
-	{ USB_DEVICE_WACOM(0xCC) },
-	{ USB_DEVICE_WACOM(0xCE) },
-	{ USB_DEVICE_WACOM(0xD0) },
-	{ USB_DEVICE_WACOM(0xD1) },
-	{ USB_DEVICE_WACOM(0xD2) },
-	{ USB_DEVICE_WACOM(0xD3) },
-	{ USB_DEVICE_WACOM(0xD4) },
-	{ USB_DEVICE_WACOM(0xD5) },
-	{ USB_DEVICE_WACOM(0xD6) },
-	{ USB_DEVICE_WACOM(0xD7) },
-	{ USB_DEVICE_WACOM(0xD8) },
-	{ USB_DEVICE_WACOM(0xDA) },
-	{ USB_DEVICE_WACOM(0xDB) },
-	{ USB_DEVICE_WACOM(0xDD) },
-	{ USB_DEVICE_WACOM(0xDE) },
-	{ USB_DEVICE_WACOM(0xDF) },
-	{ USB_DEVICE_WACOM(0xE2) },
-	{ USB_DEVICE_WACOM(0xE3) },
-	{ USB_DEVICE_WACOM(0xE5) },
-	{ USB_DEVICE_WACOM(0xE6) },
-	{ 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(0x300) },
-	{ USB_DEVICE_WACOM(0x301) },
-	{ USB_DEVICE_WACOM(0x302) },
-	{ USB_DEVICE_WACOM(0x303) },
-	{ USB_DEVICE_WACOM(0x304) },
-	{ 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) },
-	{ }
-};
-MODULE_DEVICE_TABLE(hid, wacom_ids);
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
deleted file mode 100644
index 4c59247..0000000
--- a/drivers/input/tablet/wacom_wac.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * drivers/input/tablet/wacom_wac.h
- *
- * 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.
- */
-#ifndef WACOM_WAC_H
-#define WACOM_WAC_H
-
-#include <linux/types.h>
-
-/* maximum packet length for USB devices */
-#define WACOM_PKGLEN_MAX	68
-
-#define WACOM_NAME_MAX		64
-
-/* packet length for individual models */
-#define WACOM_PKGLEN_PENPRTN	 7
-#define WACOM_PKGLEN_GRAPHIRE	 8
-#define WACOM_PKGLEN_BBFUN	 9
-#define WACOM_PKGLEN_INTUOS	10
-#define WACOM_PKGLEN_TPC1FG	 5
-#define WACOM_PKGLEN_TPC1FG_B	10
-#define WACOM_PKGLEN_TPC2FG	14
-#define WACOM_PKGLEN_BBTOUCH	20
-#define WACOM_PKGLEN_BBTOUCH3	64
-#define WACOM_PKGLEN_BBPEN	10
-#define WACOM_PKGLEN_WIRELESS	32
-#define WACOM_PKGLEN_MTOUCH	62
-#define WACOM_PKGLEN_MTTPC	40
-#define WACOM_PKGLEN_DTUS	68
-#define WACOM_PKGLEN_PENABLED	 8
-
-/* wacom data size per MT contact */
-#define WACOM_BYTES_PER_MT_PACKET	11
-#define WACOM_BYTES_PER_24HDT_PACKET	14
-
-/* device IDs */
-#define STYLUS_DEVICE_ID	0x02
-#define TOUCH_DEVICE_ID		0x03
-#define CURSOR_DEVICE_ID	0x06
-#define ERASER_DEVICE_ID	0x0A
-#define PAD_DEVICE_ID		0x0F
-
-/* wacom data packet report IDs */
-#define WACOM_REPORT_PENABLED		2
-#define WACOM_REPORT_INTUOSREAD		5
-#define WACOM_REPORT_INTUOSWRITE	6
-#define WACOM_REPORT_INTUOSPAD		12
-#define WACOM_REPORT_INTUOS5PAD		3
-#define WACOM_REPORT_DTUSPAD		21
-#define WACOM_REPORT_TPC1FG		6
-#define WACOM_REPORT_TPC2FG		13
-#define WACOM_REPORT_TPCMT		13
-#define WACOM_REPORT_TPCMT2		3
-#define WACOM_REPORT_TPCHID		15
-#define WACOM_REPORT_TPCST		16
-#define WACOM_REPORT_DTUS		17
-#define WACOM_REPORT_TPC1FGE		18
-#define WACOM_REPORT_24HDT		1
-#define WACOM_REPORT_WL			128
-#define WACOM_REPORT_USB		192
-
-/* device quirks */
-#define WACOM_QUIRK_MULTI_INPUT		0x0001
-#define WACOM_QUIRK_BBTOUCH_LOWRES	0x0002
-#define WACOM_QUIRK_NO_INPUT		0x0004
-#define WACOM_QUIRK_MONITOR		0x0008
-
-enum {
-	PENPARTNER = 0,
-	GRAPHIRE,
-	WACOM_G4,
-	PTU,
-	PL,
-	DTU,
-	DTUS,
-	INTUOS,
-	INTUOS3S,
-	INTUOS3,
-	INTUOS3L,
-	INTUOS4S,
-	INTUOS4,
-	INTUOS4L,
-	INTUOS5S,
-	INTUOS5,
-	INTUOS5L,
-	INTUOSPS,
-	INTUOSPM,
-	INTUOSPL,
-	INTUOSHT,
-	WACOM_21UX2,
-	WACOM_22HD,
-	DTK,
-	WACOM_24HD,
-	CINTIQ_HYBRID,
-	CINTIQ,
-	WACOM_BEE,
-	WACOM_13HD,
-	WACOM_MO,
-	WIRELESS,
-	BAMBOO_PT,
-	WACOM_24HDT,
-	TABLETPC,   /* add new TPC below */
-	TABLETPCE,
-	TABLETPC2FG,
-	MTSCREEN,
-	MTTPC,
-	MTTPC_B,
-	MAX_TYPE
-};
-
-struct wacom_features {
-	const char *name;
-	int x_max;
-	int y_max;
-	int pressure_max;
-	int distance_max;
-	int type;
-	int x_resolution;
-	int y_resolution;
-	int x_min;
-	int y_min;
-	int device_type;
-	int x_phy;
-	int y_phy;
-	unsigned unit;
-	int unitExpo;
-	int x_fuzz;
-	int y_fuzz;
-	int pressure_fuzz;
-	int distance_fuzz;
-	unsigned quirks;
-	unsigned touch_max;
-	int oVid;
-	int oPid;
-	int pktlen;
-	bool check_for_hid_type;
-	int hid_type;
-};
-
-struct wacom_shared {
-	bool stylus_in_proximity;
-	bool touch_down;
-	/* for wireless device to access USB interfaces */
-	unsigned touch_max;
-	int type;
-	struct input_dev *touch_input;
-};
-
-struct wacom_wac {
-	char name[WACOM_NAME_MAX];
-	char pad_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;
-};
-
-#endif
-- 
2.0.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ