Discussion:
[Linuxwacom-devel] [PATCH input-wacom 02/12] backport: HID: wacom: remove warning while disconnecting devices
Aaron Armstrong Skomra
2017-02-14 17:46:25 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

When the LED class gets removed, it actually tries to reset the LED.
However, the device being disconnected, the set_report fails.

Previously, the attempt to cut lose this last event was through unsetting
the HID drvdata, but it was not working properly. Simply reset the LED
groups to NULL makes a more efficient solution.

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Jason Gerecke <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (c0265a9)]
Signed-off-by: Jason Gerecke <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (fa2a43d)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom_sys.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 89cc6a4..e03b69c 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -2353,6 +2353,8 @@ static void wacom_remove(struct hid_device *hdev)
#endif
wacom_remove_shared_data(wacom);

+ /* make sure we don't trigger the LEDs */
+ wacom_led_groups_release(wacom);
wacom_release_resources(wacom);

hid_set_drvdata(hdev, NULL);
--
2.7.4
Aaron Armstrong Skomra
2017-02-14 17:46:27 UTC
Permalink
From: Jason Gerecke <***@gmail.com>

There no reason a Bluetooth device with the appropriate HID descriptor couldn't
be used through the HID_GENERIC codepath in the future. Ensure that the driver
attempts to bind to these devices.

Signed-off-by: Jason Gerecke <***@wacom.com>
Reviewed-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (b9e0625)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (50e75e3)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom_wac.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 496f8ae..988376e 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -4043,6 +4043,7 @@ const struct hid_device_id wacom_ids[] = {

{ USB_DEVICE_WACOM(HID_ANY_ID) },
{ I2C_DEVICE_WACOM(HID_ANY_ID) },
+ { BT_DEVICE_WACOM(HID_ANY_ID) },
{ }
};
MODULE_DEVICE_TABLE(hid, wacom_ids);
--
2.7.4
Aaron Armstrong Skomra
2017-02-14 17:46:28 UTC
Permalink
From: Jason Gerecke <***@gmail.com>

Centralize our definition of report IDs by moving those for device commands
into wacom_wac.h alongside those for input reports.

Signed-off-by: Jason Gerecke <***@wacom.com>
Reviewed-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (5ba13c6)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (2160f8c)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom_sys.c | 8 --------
3.17/wacom_wac.h | 9 +++++++++
2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index e3515fc..21dde40 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -16,15 +16,7 @@
#include <linux/input/mt.h>

#define WAC_MSG_RETRIES 5
-
-#define WAC_CMD_WL_LED_CONTROL 0x03
-#define WAC_CMD_LED_CONTROL 0x20
-#define WAC_CMD_ICON_START 0x21
-#define WAC_CMD_ICON_XFER 0x23
-#define WAC_CMD_ICON_BT_XFER 0x26
#define WAC_CMD_RETRIES 10
-#define WAC_CMD_DELETE_PAIRING 0x20
-#define WAC_CMD_UNPAIR_ALL 0xFF

#define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP)
#define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP)
diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h
index e366f0a..ffadd54 100644
--- a/3.17/wacom_wac.h
+++ b/3.17/wacom_wac.h
@@ -72,6 +72,15 @@
#define WACOM_REPORT_REMOTE 17
#define WACOM_REPORT_INTUOSHT2_ID 8

+/* wacom command report ids */
+#define WAC_CMD_WL_LED_CONTROL 0x03
+#define WAC_CMD_LED_CONTROL 0x20
+#define WAC_CMD_ICON_START 0x21
+#define WAC_CMD_ICON_XFER 0x23
+#define WAC_CMD_ICON_BT_XFER 0x26
+#define WAC_CMD_DELETE_PAIRING 0x20
+#define WAC_CMD_UNPAIR_ALL 0xFF
+
/* device quirks */
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001
#define WACOM_QUIRK_SENSE 0x0002
--
2.7.4
Aaron Armstrong Skomra
2017-02-14 17:46:26 UTC
Permalink
From: Benjamin Tissoires <***@redhat.com>

The Intuos Pro seems to not like when we set the features right after
being powered up. Instead of waiting during probe, we can schedule the
switch mode and LED control in a deferred worker so that we don't have the
5 secs of delay from USB when the device is not accessible.

The USB timeout delays were really a pain because if you happen to unplug
the tablet while it is still waiting, you are just adding 5 second timeouts
to the USB stack. Which means that a new plug of the same tablet will also
gets delayed, and will also attempt to access the hardware while in
.probe(). So the tablet doesn't appear in the dmesg, the user unplug/replug
it to make it appearing... and so on so forth.

Really, this is for the best :)

Signed-off-by: Benjamin Tissoires <***@redhat.com>
Acked-by: Jason Gerecke <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (a544c61)]
Signed-off-by: Jason Gerecke <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (1d20317)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom.h | 1 +
3.17/wacom_sys.c | 27 ++++++++++++++++++++-------
2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/3.17/wacom.h b/3.17/wacom.h
index e9e0c16..2e6c947 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -167,6 +167,7 @@ struct wacom {
struct work_struct wireless_work;
struct work_struct battery_work;
struct work_struct remote_work;
+ struct delayed_work init_work;
struct wacom_remote *remote;
struct wacom_leds {
struct wacom_group_leds *groups;
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index e03b69c..e3515fc 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -505,11 +505,11 @@ static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed,
* from the tablet, it is necessary to switch the tablet out of this
* mode and into one which sends the full range of tablet data.
*/
-static int wacom_query_tablet_data(struct hid_device *hdev,
- struct wacom_features *features)
+static int _wacom_query_tablet_data(struct wacom *wacom)
{
- struct wacom *wacom = hid_get_drvdata(hdev);
+ struct hid_device *hdev = wacom->hdev;
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_features *features = &wacom_wac->features;

if (hdev->bus == BUS_BLUETOOTH)
return wacom_bt_query_tablet_data(hdev, 1, features);
@@ -1209,11 +1209,23 @@ static int wacom_initialize_leds(struct wacom *wacom)
"cannot create sysfs group err: %d\n", error);
return error;
}
- wacom_led_control(wacom);

return 0;
}

+static void wacom_init_work(struct work_struct *work)
+{
+ struct wacom *wacom = container_of(work, struct wacom, init_work.work);
+
+ _wacom_query_tablet_data(wacom);
+ wacom_led_control(wacom);
+}
+
+static void wacom_query_tablet_data(struct wacom *wacom)
+{
+ schedule_delayed_work(&wacom->init_work, msecs_to_jiffies(1000));
+}
+
static enum power_supply_property wacom_battery_props[] = {
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_PRESENT,
@@ -1951,7 +1963,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)

if (!wireless) {
/* Note that if query fails it is not a hard failure */
- wacom_query_tablet_data(hdev, features);
+ wacom_query_tablet_data(wacom);
}

/* touch only Bamboo doesn't support pen */
@@ -2302,6 +2314,7 @@ static int wacom_probe(struct hid_device *hdev,
wacom->usbdev = dev;
wacom->intf = intf;
mutex_init(&wacom->lock);
+ INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work);
INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
INIT_WORK(&wacom->battery_work, wacom_battery_work);
INIT_WORK(&wacom->remote_work, wacom_remote_work);
@@ -2343,6 +2356,7 @@ static void wacom_remove(struct hid_device *hdev)

hid_hw_stop(hdev);

+ cancel_delayed_work_sync(&wacom->init_work);
cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work);
cancel_work_sync(&wacom->remote_work);
@@ -2364,12 +2378,11 @@ static void wacom_remove(struct hid_device *hdev)
static int wacom_resume(struct hid_device *hdev)
{
struct wacom *wacom = hid_get_drvdata(hdev);
- struct wacom_features *features = &wacom->wacom_wac.features;

mutex_lock(&wacom->lock);

/* switch to wacom mode first */
- wacom_query_tablet_data(hdev, features);
+ _wacom_query_tablet_data(wacom);
wacom_led_control(wacom);

mutex_unlock(&wacom->lock);
--
2.7.4
Aaron Armstrong Skomra
2017-02-14 17:46:34 UTC
Permalink
Add support for the LEDs around the mode switch to the generic code path in
support of the second generation Intuos Pro.

Backport note: Kernel control of the LED mode switch is not present in
kernels before 4.5, and the WACOM_HID_WD_BUTTONCENTER usage is mapped,
but not handled specially by the driver here.

Signed-off-by: Aaron Skomra <***@wacom.com>
Reviewed-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (10c55ca)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (fc3d6d5)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom.h | 2 ++
3.17/wacom_sys.c | 38 +++++++++++++++++++++++++++++++++++---
3.17/wacom_wac.c | 11 ++++++++++-
3.17/wacom_wac.h | 1 +
4 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/3.17/wacom.h b/3.17/wacom.h
index 100cad4..8adc02c 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -169,6 +169,7 @@ struct wacom {
struct work_struct remote_work;
struct delayed_work init_work;
struct wacom_remote *remote;
+ bool generic_has_leds;
struct wacom_leds {
struct wacom_group_leds *groups;
u8 llv; /* status led brightness no button (1..127) */
@@ -218,6 +219,7 @@ void wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
void wacom_wac_report(struct hid_device *hdev, struct hid_report *report);
void wacom_battery_work(struct work_struct *work);
int wacom_equivalent_usage(int usage);
+int wacom_initialize_leds(struct wacom *wacom);

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
static int wacom_hid_report_len(struct hid_report *report)
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 13b1ee7..6d1a380 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -779,8 +779,13 @@ static int wacom_led_control(struct wacom *wacom)
if (!buf)
return -ENOMEM;

- if (wacom->wacom_wac.features.type >= INTUOS5S &&
- wacom->wacom_wac.features.type <= INTUOSPL) {
+ if (wacom->wacom_wac.features.type == HID_GENERIC) {
+ buf[0] = WAC_CMD_LED_CONTROL_GENERIC;
+ buf[1] = wacom->led.llv;
+ buf[2] = wacom->led.groups[0].select & 0x03;
+
+ } else if ((wacom->wacom_wac.features.type >= INTUOS5S &&
+ wacom->wacom_wac.features.type <= INTUOSPL)) {
/*
* Touch Ring and crop mark LED luminance may take on
* one of four values:
@@ -1050,6 +1055,17 @@ static struct attribute_group intuos5_led_attr_group = {
.attrs = intuos5_led_attrs,
};

+static struct attribute *generic_led_attrs[] = {
+ &dev_attr_status0_luminance.attr,
+ &dev_attr_status_led0_select.attr,
+ NULL
+};
+
+static struct attribute_group generic_led_attr_group = {
+ .name = "wacom_led",
+ .attrs = generic_led_attrs,
+};
+
struct wacom_sysfs_group_devres {
struct attribute_group *group;
struct kobject *root;
@@ -1138,7 +1154,7 @@ static int wacom_led_groups_allocate(struct wacom *wacom, int count)
return 0;
}

-static int wacom_initialize_leds(struct wacom *wacom)
+int wacom_initialize_leds(struct wacom *wacom)
{
int error;

@@ -1147,6 +1163,22 @@ static int wacom_initialize_leds(struct wacom *wacom)

/* Initialize default values */
switch (wacom->wacom_wac.features.type) {
+ case HID_GENERIC:
+ if (!wacom->generic_has_leds)
+ return 0;
+ wacom->led.llv = 100;
+
+ error = wacom_led_groups_allocate(wacom, 1);
+ if (error) {
+ hid_err(wacom->hdev,
+ "cannot create leds err: %d\n", error);
+ return error;
+ }
+
+ error = wacom_devm_sysfs_create_group(wacom,
+ &generic_led_attr_group);
+ break;
+
case INTUOS4S:
case INTUOS4:
case INTUOS4WL:
diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 09dabbf..c51631a 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -1725,12 +1725,14 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
wacom_map_usage(input, usage, field, EV_ABS, ABS_Z, 0);
features->device_type |= WACOM_DEVICETYPE_PAD;
break;
+ case WACOM_HID_WD_BUTTONCENTER:
+ wacom->generic_has_leds = true;
+ /* fall through */
case WACOM_HID_WD_BUTTONHOME:
case WACOM_HID_WD_BUTTONUP:
case WACOM_HID_WD_BUTTONDOWN:
case WACOM_HID_WD_BUTTONLEFT:
case WACOM_HID_WD_BUTTONRIGHT:
- case WACOM_HID_WD_BUTTONCENTER:
wacom_map_usage(input, usage, field, EV_KEY,
wacom_numbered_button_to_key(features->numbered_buttons),
0);
@@ -1834,6 +1836,13 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
input_sync(wacom_wac->shared->touch_input);
}
break;
+
+ case WACOM_HID_WD_BUTTONCENTER:
+ /*
+ * In kernels before 4.5, changing the LED is
+ * handled by gnome-settings-daemon.
+ */
+ /* fall through */
default:
input_event(input, usage->type, usage->code, value);
break;
diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h
index e3ac560..b7e2fd3 100644
--- a/3.17/wacom_wac.h
+++ b/3.17/wacom_wac.h
@@ -79,6 +79,7 @@
#define WAC_CMD_ICON_XFER 0x23
#define WAC_CMD_ICON_BT_XFER 0x26
#define WAC_CMD_DELETE_PAIRING 0x20
+#define WAC_CMD_LED_CONTROL_GENERIC 0x32
#define WAC_CMD_UNPAIR_ALL 0xFF
#define WAC_CMD_WL_INTUOSP2 0x82
--
2.7.4
Aaron Armstrong Skomra
2017-02-14 17:46:30 UTC
Permalink
Input_event_flag duplicates the information we track in
wacom_wac->hid_data.inrange_state for the pad.

Signed-off-by: Aaron Skomra <***@wacom.com>
Reviewed-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (65ef4c1)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (f0725f3)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom_wac.c | 9 +--------
3.17/wacom_wac.h | 1 -
2 files changed, 1 insertion(+), 9 deletions(-)

diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index ad4ea52..5cb86ee 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -1783,7 +1783,6 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct input_dev *input = wacom_wac->pad_input;
- struct wacom_features *features = &wacom_wac->features;
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);

if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) {
@@ -1795,7 +1794,6 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
break;

default:
- features->input_event_flag = true;
input_event(input, usage->type, usage->code, value);
break;
}
@@ -1833,20 +1831,15 @@ static void wacom_wac_pad_report(struct hid_device *hdev,
{
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
- struct wacom_features *features = &wacom_wac->features;
struct input_dev *input = wacom_wac->pad_input;
bool active = wacom_wac->hid_data.inrange_state != 0;

/* report prox for expresskey events */
if (wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) {
- features->input_event_flag = true;
input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
- }
-
- if (features->input_event_flag) {
- features->input_event_flag = false;
input_sync(input);
}
+
}

static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h
index 76dda30..1937664 100644
--- a/3.17/wacom_wac.h
+++ b/3.17/wacom_wac.h
@@ -259,7 +259,6 @@ struct wacom_features {
int pktlen;
bool check_for_hid_type;
int hid_type;
- bool input_event_flag;
};

struct wacom_shared {
--
2.7.4
Aaron Armstrong Skomra
2017-02-14 17:46:35 UTC
Permalink
From: Ping Cheng <***@gmail.com>

Non-generic devices have numbered_buttons set for both pen and
touch interfaces by default. The actual number of buttons on the
interface is normally manually decided later, which is different
from what those HID generic devices are processed, where number
of buttons are directly retrieved from HID descriptors.

This patch adds the missed HID_GENERIC check and moves the statement
to wacom_setup_pad_input_capabilities since it's not a quirk anymore.

Signed-off-by: Ping Cheng <***@wacom.com>
Reviewed-by: Jason Gerecke <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (e7deb15)]
Signed-off-by: Jason Gerecke <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (da8bf11)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom_wac.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index c51631a..acab3b3 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -2997,8 +2997,6 @@ void wacom_setup_device_quirks(struct wacom *wacom)
struct wacom_features *features = &wacom->wacom_wac.features;

/* The pen and pad share the same interface on most devices */
- if (features->numbered_buttons > 0)
- features->device_type |= WACOM_DEVICETYPE_PAD;
if (features->type == GRAPHIRE_BT || features->type == WACOM_G4 ||
features->type == DTUS ||
(features->type >= INTUOS3S && features->type <= WACOM_MO)) {
@@ -3446,6 +3444,9 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
{
struct wacom_features *features = &wacom_wac->features;

+ if ((features->type == HID_GENERIC) && features->numbered_buttons > 0)
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+
if (!(features->device_type & WACOM_DEVICETYPE_PAD))
return -ENODEV;
--
2.7.4
Aaron Armstrong Skomra
2017-02-14 17:46:33 UTC
Permalink
The second generation Intuos Pro is the first device in the generic codepath
which has a touchswitch. We utilize a flag in wacom_shared in order to report
this switch event received from the pad on the touch input.

Signed-off-by: Aaron Skomra <***@wacom.com>
Reviewed-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (d2ec58a)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (a67a876)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom_sys.c | 26 +++++++++++++++++++-------
3.17/wacom_wac.c | 19 ++++++++++++++++++-
3.17/wacom_wac.h | 4 +++-
3 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index c7e5277..13b1ee7 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -1884,6 +1884,24 @@ static void wacom_release_resources(struct wacom *wacom)
wacom->wacom_wac.pad_input = NULL;
}

+static void wacom_set_shared_values(struct wacom_wac *wacom_wac)
+{
+ if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) {
+ wacom_wac->shared->type = wacom_wac->features.type;
+ wacom_wac->shared->touch_input = wacom_wac->touch_input;
+ }
+
+ if (wacom_wac->has_mute_touch_switch)
+ wacom_wac->shared->has_mute_touch_switch = true;
+
+ if (wacom_wac->shared->has_mute_touch_switch &&
+ wacom_wac->shared->touch_input) {
+ set_bit(EV_SW, wacom_wac->shared->touch_input->evbit);
+ input_set_capability(wacom_wac->shared->touch_input, EV_SW,
+ SW_MUTE_DEVICE);
+ }
+}
+
static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
{
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
@@ -2007,13 +2025,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
error = hid_hw_open(hdev);

- if ((wacom_wac->features.type == INTUOSHT ||
- wacom_wac->features.type == INTUOSHT2) &&
- (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)) {
- wacom_wac->shared->type = wacom_wac->features.type;
- wacom_wac->shared->touch_input = wacom_wac->touch_input;
- }
-
+ wacom_set_shared_values(wacom_wac);
devres_close_group(&hdev->dev, wacom);

return 0;
diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 1f301ce..09dabbf 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -1738,7 +1738,17 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
features->device_type |= WACOM_DEVICETYPE_PAD;
break;
case WACOM_HID_WD_TOUCHONOFF:
- wacom_map_usage(input, usage, field, EV_SW, SW_MUTE_DEVICE, 0);
+ /*
+ * This usage, which is used to mute touch events, comes
+ * from the pad packet, but is reported on the touch
+ * interface. Because the touch interface may not have
+ * been created yet, we cannot call wacom_map_usage(). In
+ * order to process this usage when we receive it, we set
+ * the usage type and code directly.
+ */
+ wacom_wac->has_mute_touch_switch = true;
+ usage->type = EV_SW;
+ usage->code = SW_MUTE_DEVICE;
features->device_type |= WACOM_DEVICETYPE_PAD;
break;
case WACOM_HID_WD_TOUCHSTRIP:
@@ -1817,6 +1827,13 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
input_event(input, usage->type, usage->code, 0);
break;

+ case WACOM_HID_WD_TOUCHONOFF:
+ if (wacom_wac->shared->touch_input) {
+ input_report_switch(wacom_wac->shared->touch_input,
+ SW_MUTE_DEVICE, !value);
+ input_sync(wacom_wac->shared->touch_input);
+ }
+ break;
default:
input_event(input, usage->type, usage->code, value);
break;
diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h
index 3c6e400..e3ac560 100644
--- a/3.17/wacom_wac.h
+++ b/3.17/wacom_wac.h
@@ -131,6 +131,7 @@
#define WACOM_HID_WD_ACCELEROMETER_Y (WACOM_HID_UP_WACOMDIGITIZER | 0x0402)
#define WACOM_HID_WD_ACCELEROMETER_Z (WACOM_HID_UP_WACOMDIGITIZER | 0x0403)
#define WACOM_HID_WD_BATTERY_CHARGING (WACOM_HID_UP_WACOMDIGITIZER | 0x0404)
+#define WACOM_HID_WD_TOUCHONOFF (WACOM_HID_UP_WACOMDIGITIZER | 0x0454)
#define WACOM_HID_WD_BATTERY_LEVEL (WACOM_HID_UP_WACOMDIGITIZER | 0x043b)
#define WACOM_HID_WD_EXPRESSKEY00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0910)
#define WACOM_HID_WD_EXPRESSKEYCAP00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0950)
@@ -140,7 +141,6 @@
#define WACOM_HID_WD_BUTTONLEFT (WACOM_HID_UP_WACOMDIGITIZER | 0x0993)
#define WACOM_HID_WD_BUTTONRIGHT (WACOM_HID_UP_WACOMDIGITIZER | 0x0994)
#define WACOM_HID_WD_BUTTONCENTER (WACOM_HID_UP_WACOMDIGITIZER | 0x0995)
-#define WACOM_HID_WD_TOUCHONOFF (WACOM_HID_UP_WACOMDIGITIZER | 0x0996)
#define WACOM_HID_WD_FINGERWHEEL (WACOM_HID_UP_WACOMDIGITIZER | 0x0d03)
#define WACOM_HID_WD_OFFSETLEFT (WACOM_HID_UP_WACOMDIGITIZER | 0x0d30)
#define WACOM_HID_WD_OFFSETTOP (WACOM_HID_UP_WACOMDIGITIZER | 0x0d31)
@@ -284,6 +284,7 @@ struct wacom_shared {
struct input_dev *touch_input;
struct hid_device *pen;
struct hid_device *touch;
+ bool has_mute_touch_switch;
};

struct hid_data {
@@ -341,6 +342,7 @@ struct wacom_wac {
int mode_value;
struct work_struct intuos_prox_event_worker;
struct hid_data hid_data;
+ bool has_mute_touch_switch;
};

#endif
--
2.7.4
Aaron Armstrong Skomra
2017-02-14 17:46:29 UTC
Permalink
From: Jason Gerecke <***@gmail.com>

In addition to its USB interface, the second-generation Intuos Pro
includes a Bluetooth radio that offers two pairing interfaces: classic
and low-energy. The classic interface functions just like the earlier
Bluetooth-enabled Intuos4 and Graphire4 tablets, appearing as a HID device
that our driver can work with. The low-energy interface is intented to
be used by userspace applications that make use of its paper-to-digital
capabilities.

Despite the USB interface using Wacom's new vendor-defined HID usages,
the Bluetooth interface provides us with useless black-box "blob"
report descriptors like past devices. We thus have to explicitly add
support for the PIDs and reports used.

These devices pack a /lot/ of information into a single Bluetooth
input report. Each report contains up to seven snapshots of the pen
state, four snapshots of the touch state (of five touches each), pad
state, and battery data. Thankfully this isn't too hard for the driver
to report -- it just takes a fair amount of code to extract!

Signed-off-by: Jason Gerecke <***@wacom.com>
Reviewed-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (4922cd2)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (75adeee)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom_sys.c | 25 +++++++
3.17/wacom_wac.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3.17/wacom_wac.h | 6 +-
3 files changed, 226 insertions(+), 2 deletions(-)

diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index 21dde40..a43b12e 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -764,6 +764,10 @@ static int wacom_led_control(struct wacom *wacom)
report_id = WAC_CMD_WL_LED_CONTROL;
buf_size = 13;
}
+ else if (wacom->wacom_wac.features.type == INTUOSP2_BT) {
+ report_id = WAC_CMD_WL_INTUOSP2;
+ buf_size = 51;
+ }
buf = kzalloc(buf_size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -789,6 +793,16 @@ static int wacom_led_control(struct wacom *wacom)
} else
buf[1] = led_bits;
}
+ else if (wacom->wacom_wac.features.type == INTUOSP2_BT) {
+ buf[0] = report_id;
+ buf[4] = 100; // Power Connection LED (ORANGE)
+ buf[5] = 100; // BT Connection LED (BLUE)
+ buf[6] = 100; // Paper Mode (RED?)
+ buf[7] = 100; // Paper Mode (GREEN?)
+ buf[8] = 100; // Paper Mode (BLUE?)
+ buf[9] = wacom->led.llv;
+ buf[10] = wacom->led.groups[0].select & 0x03;
+ }
else {
int led = wacom->led.groups[0].select | 0x4;

@@ -1183,6 +1197,17 @@ static int wacom_initialize_leds(struct wacom *wacom)
&intuos5_led_attr_group);
break;

+ case INTUOSP2_BT:
+ wacom->led.llv = 50;
+ wacom->led.max_llv = 100;
+ error = wacom_leds_alloc_and_register(wacom, 1, 4, false);
+ if (error) {
+ hid_err(wacom->hdev,
+ "cannot create leds err: %d\n", error);
+ return error;
+ }
+ return 0;
+
case REMOTE:
error = wacom_led_groups_allocate(wacom, 5);
if (error) {
diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 988376e..ad4ea52 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -1199,6 +1199,161 @@ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom)
return count;
}

+static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
+{
+ const int pen_frame_len = 14;
+ const int pen_frames = 7;
+
+ struct input_dev *pen_input = wacom->pen_input;
+ unsigned char *data = wacom->data;
+ int i;
+
+ wacom->serial[0] = get_unaligned_le64(&data[99]);
+ wacom->id[0] = get_unaligned_le16(&data[107]);
+ if (wacom->serial[0] >> 52 == 1) {
+ /* Add back in missing bits of ID for non-USI pens */
+ wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF;
+ }
+ wacom->tool[0] = wacom_intuos_get_tool_type(wacom_intuos_id_mangle(wacom->id[0]));
+
+ for (i = 0; i < pen_frames; i++) {
+ unsigned char *frame = &data[i*pen_frame_len + 1];
+
+ if (!(frame[0] & 0x80))
+ continue;
+
+ input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
+ input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
+ input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
+ input_report_abs(pen_input, ABS_TILT_X, frame[7]);
+ input_report_abs(pen_input, ABS_TILT_Y, frame[8]);
+ input_report_abs(pen_input, ABS_Z, get_unaligned_le16(&frame[9]));
+ input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11]));
+ input_report_abs(pen_input, ABS_DISTANCE, frame[13]);
+
+ input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x01);
+ input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02);
+ input_report_key(pen_input, BTN_STYLUS2, frame[0] & 0x04);
+
+ input_report_key(pen_input, wacom->tool[0], 1);
+ input_event(pen_input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
+ input_report_abs(pen_input, ABS_MISC,
+ wacom_intuos_id_mangle(wacom->id[0])); /* report tool id */
+
+ wacom->shared->stylus_in_proximity = frame[0] & 0x40;
+
+ input_sync(pen_input);
+ }
+}
+
+static void wacom_intuos_pro2_bt_touch(struct wacom_wac *wacom)
+{
+ const int finger_touch_len = 8;
+ const int finger_frames = 4;
+ const int finger_frame_len = 43;
+
+ struct input_dev *touch_input = wacom->touch_input;
+ unsigned char *data = wacom->data;
+ int num_contacts_left = 5;
+ int i, j;
+
+ for (i = 0; i < finger_frames; i++) {
+ unsigned char *frame = &data[i*finger_frame_len + 109];
+ int current_num_contacts = frame[0] & 0x7F;
+ int contacts_to_send;
+
+ if (!(frame[0] & 0x80))
+ continue;
+
+ /*
+ * First packet resets the counter since only the first
+ * packet in series will have non-zero current_num_contacts.
+ */
+ if (current_num_contacts)
+ wacom->num_contacts_left = current_num_contacts;
+
+ contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
+
+ for (j = 0; j < contacts_to_send; j++) {
+ unsigned char *touch = &frame[j*finger_touch_len + 1];
+ int slot = input_mt_get_slot_by_key(touch_input, touch[0]);
+ int x = get_unaligned_le16(&touch[2]);
+ int y = get_unaligned_le16(&touch[4]);
+ int w = touch[6] * input_abs_get_res(touch_input, ABS_MT_POSITION_X);
+ int h = touch[7] * input_abs_get_res(touch_input, ABS_MT_POSITION_Y);
+
+ if (slot < 0)
+ continue;
+
+ input_mt_slot(touch_input, slot);
+ input_mt_report_slot_state(touch_input, MT_TOOL_FINGER, touch[1] & 0x01);
+ input_report_abs(touch_input, ABS_MT_POSITION_X, x);
+ input_report_abs(touch_input, ABS_MT_POSITION_Y, y);
+ input_report_abs(touch_input, ABS_MT_TOUCH_MAJOR, max(w, h));
+ input_report_abs(touch_input, ABS_MT_TOUCH_MINOR, min(w, h));
+ input_report_abs(touch_input, ABS_MT_ORIENTATION, w > h);
+ }
+
+ input_mt_sync_frame(touch_input);
+
+ wacom->num_contacts_left -= contacts_to_send;
+ if (wacom->num_contacts_left <= 0) {
+ wacom->num_contacts_left = 0;
+ wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
+ }
+ }
+
+ input_report_switch(touch_input, SW_MUTE_DEVICE, !(data[281] >> 7));
+ input_sync(touch_input);
+}
+
+static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom)
+{
+ struct input_dev *pad_input = wacom->pad_input;
+ unsigned char *data = wacom->data;
+
+ int buttons = (data[282] << 1) | ((data[281] >> 6) & 0x01);
+ int ring = data[285];
+ int prox = buttons | (ring & 0x80);
+
+ wacom_report_numbered_buttons(pad_input, 9, buttons);
+
+ input_report_abs(pad_input, ABS_WHEEL, (ring & 0x80) ? (ring & 0x7f) : 0);
+
+ input_report_key(pad_input, wacom->tool[1], prox ? 1 : 0);
+ input_report_abs(pad_input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
+ input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff);
+
+ input_sync(pad_input);
+}
+
+static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom)
+{
+ unsigned char *data = wacom->data;
+
+ bool chg = data[284] & 0x80;
+ int battery_status = data[284] & 0x7F;
+
+ wacom_notify_battery(wacom, battery_status, chg, 1, chg);
+}
+
+static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
+{
+ unsigned char *data = wacom->data;
+
+ if (data[0] != 0x80) {
+ dev_dbg(wacom->pen_input->dev.parent,
+ "%s: received unknown report #%d\n", __func__, data[0]);
+ return 0;
+ }
+
+ wacom_intuos_pro2_bt_pen(wacom);
+ wacom_intuos_pro2_bt_touch(wacom);
+ wacom_intuos_pro2_bt_pad(wacom);
+ wacom_intuos_pro2_bt_battery(wacom);
+ return 0;
+}
+
static int wacom_24hdt_irq(struct wacom_wac *wacom)
{
struct input_dev *input = wacom->touch_input;
@@ -2677,6 +2832,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
sync = wacom_intuos_irq(wacom_wac);
break;

+ case INTUOSP2_BT:
+ sync = wacom_intuos_pro2_bt_irq(wacom_wac, len);
+ break;
+
case TABLETPC:
case TABLETPCE:
case TABLETPC2FG:
@@ -2851,6 +3010,13 @@ void wacom_setup_device_quirks(struct wacom *wacom)
if (features->type == REMOTE)
features->device_type = WACOM_DEVICETYPE_PAD;

+ if (features->type == INTUOSP2_BT) {
+ features->device_type |= WACOM_DEVICETYPE_PEN |
+ WACOM_DEVICETYPE_PAD |
+ WACOM_DEVICETYPE_TOUCH;
+ features->quirks |= WACOM_QUIRK_BATTERY;
+ }
+
switch (features->type) {
case PL:
case DTU:
@@ -2997,6 +3163,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
case INTUOSPL:
case INTUOS5S:
case INTUOSPS:
+ case INTUOSP2_BT:
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
features->distance_max,
features->distance_fuzz, 0);
@@ -3108,6 +3275,27 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
}

switch (features->type) {
+ case INTUOSP2_BT:
+ input_dev->evbit[0] |= BIT_MASK(EV_SW);
+ __set_bit(SW_MUTE_DEVICE, input_dev->swbit);
+
+ if (wacom_wac->shared->touch->product == 0x361) {
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ 0, 12440, 4, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, 8640, 4, 0);
+ }
+ else if (wacom_wac->shared->touch->product == 0x360) {
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ 0, 8960, 4, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, 5920, 4, 0);
+ }
+ input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
+ input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
+
+ /* fall through */
+
case INTUOS5:
case INTUOS5L:
case INTUOSPM:
@@ -3311,6 +3499,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
case INTUOSPL:
case INTUOS5S:
case INTUOSPS:
+ case INTUOSP2_BT:
input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
break;

@@ -3869,6 +4058,12 @@ static const struct wacom_features wacom_features_0x343 =
DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
+static const struct wacom_features wacom_features_0x360 =
+ { "Wacom Intuos Pro M", 44800, 29600, 8191, 63,
+ INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 };
+static const struct wacom_features wacom_features_0x361 =
+ { "Wacom Intuos Pro L", 62200, 43200, 8191, 63,
+ INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 };

static const struct wacom_features wacom_features_HID_ANY_ID =
{ "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
@@ -4035,6 +4230,8 @@ const struct hid_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x33D) },
{ USB_DEVICE_WACOM(0x33E) },
{ USB_DEVICE_WACOM(0x343) },
+ { BT_DEVICE_WACOM(0x360) },
+ { BT_DEVICE_WACOM(0x361) },
{ USB_DEVICE_WACOM(0x4001) },
{ USB_DEVICE_WACOM(0x4004) },
{ USB_DEVICE_WACOM(0x5000) },
diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h
index ffadd54..76dda30 100644
--- a/3.17/wacom_wac.h
+++ b/3.17/wacom_wac.h
@@ -12,8 +12,8 @@
#include <linux/types.h>
#include <linux/hid.h>

-/* maximum packet length for USB devices */
-#define WACOM_PKGLEN_MAX 192
+/* maximum packet length for USB/BT devices */
+#define WACOM_PKGLEN_MAX 361

#define WACOM_NAME_MAX 64
#define WACOM_MAX_REMOTES 5
@@ -80,6 +80,7 @@
#define WAC_CMD_ICON_BT_XFER 0x26
#define WAC_CMD_DELETE_PAIRING 0x20
#define WAC_CMD_UNPAIR_ALL 0xFF
+#define WAC_CMD_WL_INTUOSP2 0x82

/* device quirks */
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001
@@ -195,6 +196,7 @@ enum {
INTUOSPS,
INTUOSPM,
INTUOSPL,
+ INTUOSP2_BT,
WACOM_21UX2,
WACOM_22HD,
DTK,
--
2.7.4
Aaron Armstrong Skomra
2017-02-14 17:46:31 UTC
Permalink
Add support for the touchring to the generic code path in support of the second
generation Intuos Pro.

We also add checks for usage->type to ensure that we handle the usage before we
report it, or change the inrange_state based on it.

Signed-off-by: Aaron Skomra <***@wacom.com>
Reviewed-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (60a2218)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (0dd13ec)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom_wac.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index 5cb86ee..acc84af 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -1743,6 +1743,10 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
features->device_type |= WACOM_DEVICETYPE_PAD;
break;
+ case WACOM_HID_WD_TOUCHRINGSTATUS:
+ wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
}

switch (equivalent_usage & 0xfffffff0) {
@@ -1785,12 +1789,22 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
struct input_dev *input = wacom_wac->pad_input;
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);

+ /*
+ * Avoid reporting this event and setting inrange_state if this usage
+ * hasn't been mapped.
+ */
+ if (!usage->type)
+ return;
+
if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) {
- wacom_wac->hid_data.inrange_state |= value;
+ if (usage->hid != WACOM_HID_WD_TOUCHRING)
+ wacom_wac->hid_data.inrange_state |= value;
}

switch (equivalent_usage) {
case WACOM_HID_WD_TOUCHRINGSTATUS:
+ if (!value)
+ input_event(input, usage->type, usage->code, 0);
break;

default:
@@ -2298,6 +2312,9 @@ void wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
if (wacom->wacom_wac.features.type != HID_GENERIC)
return;

+ if (value > field->logical_maximum || value < field->logical_minimum)
+ return;
+
if (WACOM_PAD_FIELD(field)) {
wacom_wac_pad_battery_event(hdev, field, usage, value);
if (wacom->wacom_wac.pad_input)
--
2.7.4
Aaron Armstrong Skomra
2017-02-14 17:46:32 UTC
Permalink
Add vendor defined touch to support the second generation Intuos Pro.
Previously all generic Wacom devices used true HID to report their touch.

Signed-off-by: Aaron Skomra <***@wacom.com>
Reviewed-by: Ping Cheng <***@wacom.com>
Signed-off-by: Jiri Kosina <***@suse.cz>
[***@wacom.com: Imported into input-wacom repository (ac2423c)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
[***@wacom.com: Backported from input-wacom repository (5b9339e)]
Signed-off-by: Aaron Armstrong Skomra <***@wacom.com>
---
3.17/wacom.h | 1 +
3.17/wacom_sys.c | 16 +++++++++++-----
3.17/wacom_wac.c | 22 +++++++++++++++++-----
3.17/wacom_wac.h | 16 +++++++++++++++-
4 files changed, 44 insertions(+), 11 deletions(-)

diff --git a/3.17/wacom.h b/3.17/wacom.h
index 2e6c947..100cad4 100644
--- a/3.17/wacom.h
+++ b/3.17/wacom.h
@@ -217,6 +217,7 @@ void wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value);
void wacom_wac_report(struct hid_device *hdev, struct hid_report *report);
void wacom_battery_work(struct work_struct *work);
+int wacom_equivalent_usage(int usage);

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
static int wacom_hid_report_len(struct hid_report *report)
diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c
index a43b12e..c7e5277 100644
--- a/3.17/wacom_sys.c
+++ b/3.17/wacom_sys.c
@@ -112,11 +112,12 @@ static void wacom_feature_mapping(struct hid_device *hdev,
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_features *features = &wacom->wacom_wac.features;
struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
+ unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
u8 *data;
int ret;
int n;

- switch (usage->hid) {
+ switch (equivalent_usage) {
case HID_DG_CONTACTMAX:
/* leave touch_max as is if predefined */
if (!features->touch_max) {
@@ -329,8 +330,14 @@ static void wacom_post_parse_hid(struct hid_device *hdev,
if (features->type == HID_GENERIC) {
/* Any last-minute generic device setup */
if (features->touch_max > 1) {
- input_mt_init_slots(wacom_wac->touch_input, wacom_wac->features.touch_max,
- INPUT_MT_DIRECT);
+ if (features->device_type & WACOM_DEVICETYPE_DIRECT)
+ input_mt_init_slots(wacom_wac->touch_input,
+ wacom_wac->features.touch_max,
+ INPUT_MT_DIRECT);
+ else
+ input_mt_init_slots(wacom_wac->touch_input,
+ wacom_wac->features.touch_max,
+ INPUT_MT_POINTER);
}
}
}
@@ -1199,8 +1206,7 @@ static int wacom_initialize_leds(struct wacom *wacom)

case INTUOSP2_BT:
wacom->led.llv = 50;
- wacom->led.max_llv = 100;
- error = wacom_leds_alloc_and_register(wacom, 1, 4, false);
+ error = wacom_led_groups_allocate(wacom, 1);
if (error) {
hid_err(wacom->hdev,
"cannot create leds err: %d\n", error);
diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c
index acc84af..1f301ce 100644
--- a/3.17/wacom_wac.c
+++ b/3.17/wacom_wac.c
@@ -1608,7 +1608,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
return 0;
}

-static int wacom_equivalent_usage(int usage)
+int wacom_equivalent_usage(int usage)
{
if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMDIGITIZER) {
int subpage = (usage & 0xFF00) << 8;
@@ -1635,6 +1635,16 @@ static int wacom_equivalent_usage(int usage)
return subpage | subusage;
}

+ if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMTOUCH) {
+ int subpage = (usage & 0xFF00) << 8;
+ int subusage = (usage & 0xFF);
+
+ if (subpage == HID_UP_UNDEFINED)
+ subpage = WACOM_HID_SP_DIGITIZER;
+
+ return subpage | subusage;
+ }
+
return usage;
}

@@ -2228,8 +2238,10 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,

for (j = 0; j < field->maxusage; j++) {
struct hid_usage *usage = &field->usage[j];
+ unsigned int equivalent_usage =
+ wacom_equivalent_usage(usage->hid);

- switch (usage->hid) {
+ switch (equivalent_usage) {
case HID_GD_X:
case HID_GD_Y:
case HID_DG_WIDTH:
@@ -2238,7 +2250,7 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
case HID_DG_INRANGE:
case HID_DG_INVERT:
case HID_DG_TIPSWITCH:
- hid_data->last_slot_field = usage->hid;
+ hid_data->last_slot_field = equivalent_usage;
break;
case HID_DG_CONTACTCOUNT:
hid_data->cc_report = report->id;
@@ -2293,8 +2305,8 @@ void wacom_wac_usage_mapping(struct hid_device *hdev,
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct wacom_features *features = &wacom_wac->features;

- /* currently, only direct devices have proper hid report descriptors */
- features->device_type |= WACOM_DEVICETYPE_DIRECT;
+ if (WACOM_DIRECT_DEVICE(field))
+ features->device_type |= WACOM_DEVICETYPE_DIRECT;

if (WACOM_PAD_FIELD(field))
wacom_wac_pad_usage_mapping(hdev, field, usage);
diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h
index 1937664..3c6e400 100644
--- a/3.17/wacom_wac.h
+++ b/3.17/wacom_wac.h
@@ -117,6 +117,7 @@
#define WACOM_HID_SP_DIGITIZER 0x000d0000
#define WACOM_HID_SP_DIGITIZERINFO 0x00100000
#define WACOM_HID_WD_DIGITIZER (WACOM_HID_UP_WACOMDIGITIZER | 0x01)
+#define WACOM_HID_WD_PEN (WACOM_HID_UP_WACOMDIGITIZER | 0x02)
#define WACOM_HID_WD_SENSE (WACOM_HID_UP_WACOMDIGITIZER | 0x36)
#define WACOM_HID_WD_DIGITIZERFNKEYS (WACOM_HID_UP_WACOMDIGITIZER | 0x39)
#define WACOM_HID_WD_SERIALHI (WACOM_HID_UP_WACOMDIGITIZER | 0x5c)
@@ -153,6 +154,12 @@
#define WACOM_HID_UP_G11 0xff110000
#define WACOM_HID_G11_PEN (WACOM_HID_UP_G11 | 0x02)
#define WACOM_HID_G11_TOUCHSCREEN (WACOM_HID_UP_G11 | 0x11)
+#define WACOM_HID_UP_WACOMTOUCH 0xff000000
+#define WACOM_HID_WT_TOUCHSCREEN (WACOM_HID_UP_WACOMTOUCH | 0x04)
+#define WACOM_HID_WT_TOUCHPAD (WACOM_HID_UP_WACOMTOUCH | 0x05)
+#define WACOM_HID_WT_CONTACTMAX (WACOM_HID_UP_WACOMTOUCH | 0x55)
+#define WACOM_HID_WT_X (WACOM_HID_UP_WACOMTOUCH | 0x130)
+#define WACOM_HID_WT_Y (WACOM_HID_UP_WACOMTOUCH | 0x131)

#define WACOM_PAD_FIELD(f) (((f)->physical == HID_DG_TABLETFUNCTIONKEY) || \
((f)->physical == WACOM_HID_WD_DIGITIZERFNKEYS) || \
@@ -170,7 +177,14 @@
((f)->physical == HID_DG_FINGER) || \
((f)->application == HID_DG_TOUCHSCREEN) || \
((f)->application == WACOM_HID_G9_TOUCHSCREEN) || \
- ((f)->application == WACOM_HID_G11_TOUCHSCREEN))
+ ((f)->application == WACOM_HID_G11_TOUCHSCREEN) || \
+ ((f)->application == WACOM_HID_WT_TOUCHPAD) || \
+ ((f)->application == HID_DG_TOUCHPAD))
+
+#define WACOM_DIRECT_DEVICE(f) (((f)->application == HID_DG_TOUCHSCREEN) || \
+ ((f)->application == WACOM_HID_WT_TOUCHSCREEN) || \
+ ((f)->application == HID_DG_PEN) || \
+ ((f)->application == WACOM_HID_WD_PEN))

enum {
PENPARTNER = 0,
--
2.7.4
Loading...