summaryrefslogtreecommitdiffstats
path: root/drivers/hid/wacom_wac.c
diff options
context:
space:
mode:
authorJason Gerecke2016-10-20 03:03:43 +0200
committerJiri Kosina2016-10-20 09:53:57 +0200
commitc9c095874ab4446be6dec6755d8f68862fdeae48 (patch)
treef061b9cb23c96716801b2e9ee98af8d456faf40c /drivers/hid/wacom_wac.c
parentHID: wacom: generic: Add support for height, tilt, and twist usages (diff)
downloadkernel-qcow2-linux-c9c095874ab4446be6dec6755d8f68862fdeae48.tar.gz
kernel-qcow2-linux-c9c095874ab4446be6dec6755d8f68862fdeae48.tar.xz
kernel-qcow2-linux-c9c095874ab4446be6dec6755d8f68862fdeae48.zip
HID: wacom: generic: Support and use 'Custom HID' mode and usages
Wacom's new "MobileStudio Pro" tablets are the first devices in their branded product line-up to include a usable HID descriptor for the pen interface. Like prior branded products, the device can operate in one of two modes: 'Standard HID', and 'Wacom Custom HID'. Although the first mode is usable by the HID_GENERIC codepath as-is (huzzah!), it is subject to some restrictions -- most notably pressure being limited to 2048 levels instead of 8192. To ensure tablets that include support for Custom HID mode work optimally, we add support for its usages and switch the device to Custom HID mode if possible. The usages defined for Custom HID mode are often numerically similar to their standard HID equivalents, allowing us to write a simple translation function that takes arbitrary HID usages as input and which returns the corresponding standard HID usage as output (if one exists). Switching on this translated usage instead of the actual usage allows the existing cases to apply to both modes of operation without having to explicitly define every Custom HID usage. Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/wacom_wac.c')
-rw-r--r--drivers/hid/wacom_wac.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 3f4ba53192c0..6c2f0e4baf7d 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1435,14 +1435,35 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
return 0;
}
+static int wacom_equivalent_usage(int usage)
+{
+ if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMDIGITIZER) {
+ int subpage = (usage & 0xFF00) << 8;
+ int subusage = (usage & 0xFF);
+
+ if (subpage == WACOM_HID_SP_DIGITIZER ||
+ subpage == WACOM_HID_SP_DIGITIZERINFO) {
+ return usage;
+ }
+
+ if (subpage == HID_UP_UNDEFINED)
+ subpage = HID_UP_DIGITIZER;
+
+ return subpage | subusage;
+ }
+
+ return usage;
+}
+
static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage,
struct hid_field *field, __u8 type, __u16 code, int fuzz)
{
int fmin = field->logical_minimum;
int fmax = field->logical_maximum;
+ unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
int resolution_code = code;
- if (usage->hid == HID_DG_TWIST) {
+ if (equivalent_usage == HID_DG_TWIST) {
resolution_code = ABS_RZ;
}
@@ -1472,8 +1493,9 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct input_dev *input = wacom_wac->pen_input;
+ unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
- switch (usage->hid) {
+ switch (equivalent_usage) {
case HID_GD_X:
wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4);
break;
@@ -1524,8 +1546,9 @@ static int wacom_wac_pen_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->pen_input;
+ unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
- switch (usage->hid) {
+ switch (equivalent_usage) {
case HID_GD_Z:
/*
* HID_GD_Z "should increase as the control's position is
@@ -1597,8 +1620,9 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct input_dev *input = wacom_wac->touch_input;
unsigned touch_max = wacom_wac->features.touch_max;
+ unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
- switch (usage->hid) {
+ switch (equivalent_usage) {
case HID_GD_X:
if (touch_max == 1)
wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4);
@@ -1673,8 +1697,9 @@ static int wacom_wac_finger_event(struct hid_device *hdev,
{
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
- switch (usage->hid) {
+ switch (equivalent_usage) {
case HID_GD_X:
wacom_wac->hid_data.x = value;
break;
@@ -1697,7 +1722,7 @@ static int wacom_wac_finger_event(struct hid_device *hdev,
if (usage->usage_index + 1 == field->report_count) {
- if (usage->hid == wacom_wac->hid_data.last_slot_field)
+ if (equivalent_usage == wacom_wac->hid_data.last_slot_field)
wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
}