Input: wacom - use full 32-bit HID Usage value in switch statement

A HID Usage is a 32-bit value: an upper 16-bit "page" and a lower 16-bit
ID. While the two halves are normally reported seperately, only the
combination uniquely idenfifes a particular HID Usage.

The existing code performs the comparison in two steps, first performing a
switch on the ID and then verifying the page within each case. While this
works fine, it is very akward to handle two Usages that share a single ID,
such as HID_USAGE_PRESSURE and HID_USAGE_X because the case statement can
only have a single identifier.

To work around this, we now check the full 32-bit HID Usage directly rather
than first checking the ID and then the page.  This allows the switch
statement to have distinct cases for e.g. HID_USAGE_PRESSURE and
HID_USAGE_X.

Signed-off-by: Jason Gerecke <killertofu@gmail.com>
Tested-by: Aaron Skomra <Aaron.Skomra@wacom.com>
Reviewed-by: Carl Worth <cworth@cworth.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
Jason Gerecke 2014-04-19 13:46:40 -07:00 committed by Dmitry Torokhov
parent 91ae0e7783
commit 5866d9e3b7
1 changed files with 103 additions and 122 deletions

View File

@ -22,23 +22,17 @@
#define HID_USAGE_PAGE_DIGITIZER 0x0d #define HID_USAGE_PAGE_DIGITIZER 0x0d
#define HID_USAGE_PAGE_DESKTOP 0x01 #define HID_USAGE_PAGE_DESKTOP 0x01
#define HID_USAGE 0x09 #define HID_USAGE 0x09
#define HID_USAGE_X 0x30 #define HID_USAGE_X ((HID_USAGE_PAGE_DESKTOP << 16) | 0x30)
#define HID_USAGE_Y 0x31 #define HID_USAGE_Y ((HID_USAGE_PAGE_DESKTOP << 16) | 0x31)
#define HID_USAGE_X_TILT 0x3d #define HID_USAGE_X_TILT ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x3d)
#define HID_USAGE_Y_TILT 0x3e #define HID_USAGE_Y_TILT ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x3e)
#define HID_USAGE_FINGER 0x22 #define HID_USAGE_FINGER ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x22)
#define HID_USAGE_STYLUS 0x20 #define HID_USAGE_STYLUS ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x20)
#define HID_USAGE_CONTACTMAX 0x55 #define HID_USAGE_CONTACTMAX ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x55)
#define HID_COLLECTION 0xa1 #define HID_COLLECTION 0xa1
#define HID_COLLECTION_LOGICAL 0x02 #define HID_COLLECTION_LOGICAL 0x02
#define HID_COLLECTION_END 0xc0 #define HID_COLLECTION_END 0xc0
enum {
WCM_UNDEFINED = 0,
WCM_DESKTOP,
WCM_DIGITIZER,
};
struct hid_descriptor { struct hid_descriptor {
struct usb_descriptor_header header; struct usb_descriptor_header header;
__le16 bcdHID; __le16 bcdHID;
@ -305,7 +299,7 @@ static int wacom_parse_hid(struct usb_interface *intf,
char limit = 0; char limit = 0;
/* result has to be defined as int for some devices */ /* result has to be defined as int for some devices */
int result = 0, touch_max = 0; int result = 0, touch_max = 0;
int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0; int i = 0, page = 0, finger = 0, pen = 0;
unsigned char *report; unsigned char *report;
report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL); report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL);
@ -332,134 +326,121 @@ static int wacom_parse_hid(struct usb_interface *intf,
switch (report[i]) { switch (report[i]) {
case HID_USAGE_PAGE: case HID_USAGE_PAGE:
switch (report[i + 1]) { page = report[i + 1];
case HID_USAGE_PAGE_DIGITIZER: i++;
usage = WCM_DIGITIZER;
i++;
break;
case HID_USAGE_PAGE_DESKTOP:
usage = WCM_DESKTOP;
i++;
break;
}
break; break;
case HID_USAGE: case HID_USAGE:
switch (report[i + 1]) { switch (page << 16 | report[i + 1]) {
case HID_USAGE_X: case HID_USAGE_X:
if (usage == WCM_DESKTOP) { if (finger) {
if (finger) { features->device_type = BTN_TOOL_FINGER;
features->device_type = BTN_TOOL_FINGER; /* touch device at least supports one touch point */
/* touch device at least supports one touch point */ touch_max = 1;
touch_max = 1; switch (features->type) {
switch (features->type) { case TABLETPC2FG:
case TABLETPC2FG: features->pktlen = WACOM_PKGLEN_TPC2FG;
features->pktlen = WACOM_PKGLEN_TPC2FG; break;
break;
case MTSCREEN: case MTSCREEN:
case WACOM_24HDT: case WACOM_24HDT:
features->pktlen = WACOM_PKGLEN_MTOUCH; features->pktlen = WACOM_PKGLEN_MTOUCH;
break; break;
case MTTPC: case MTTPC:
features->pktlen = WACOM_PKGLEN_MTTPC; features->pktlen = WACOM_PKGLEN_MTTPC;
break; break;
case BAMBOO_PT: case BAMBOO_PT:
features->pktlen = WACOM_PKGLEN_BBTOUCH; features->pktlen = WACOM_PKGLEN_BBTOUCH;
break; break;
default: default:
features->pktlen = WACOM_PKGLEN_GRAPHIRE; features->pktlen = WACOM_PKGLEN_GRAPHIRE;
break; break;
} }
switch (features->type) { switch (features->type) {
case BAMBOO_PT: case BAMBOO_PT:
features->x_phy = features->x_phy =
get_unaligned_le16(&report[i + 5]); get_unaligned_le16(&report[i + 5]);
features->x_max = features->x_max =
get_unaligned_le16(&report[i + 8]); get_unaligned_le16(&report[i + 8]);
i += 15; i += 15;
break; break;
case WACOM_24HDT: case WACOM_24HDT:
features->x_max =
get_unaligned_le16(&report[i + 3]);
features->x_phy =
get_unaligned_le16(&report[i + 8]);
features->unit = report[i - 1];
features->unitExpo = report[i - 3];
i += 12;
break;
default:
features->x_max =
get_unaligned_le16(&report[i + 3]);
features->x_phy =
get_unaligned_le16(&report[i + 6]);
features->unit = report[i + 9];
features->unitExpo = report[i + 11];
i += 12;
break;
}
} else if (pen) {
/* penabled only accepts exact bytes of data */
if (features->type >= TABLETPC)
features->pktlen = WACOM_PKGLEN_GRAPHIRE;
features->device_type = BTN_TOOL_PEN;
features->x_max = features->x_max =
get_unaligned_le16(&report[i + 3]); get_unaligned_le16(&report[i + 3]);
i += 4; features->x_phy =
get_unaligned_le16(&report[i + 8]);
features->unit = report[i - 1];
features->unitExpo = report[i - 3];
i += 12;
break;
default:
features->x_max =
get_unaligned_le16(&report[i + 3]);
features->x_phy =
get_unaligned_le16(&report[i + 6]);
features->unit = report[i + 9];
features->unitExpo = report[i + 11];
i += 12;
break;
} }
} else if (pen) {
/* penabled only accepts exact bytes of data */
if (features->type >= TABLETPC)
features->pktlen = WACOM_PKGLEN_GRAPHIRE;
features->device_type = BTN_TOOL_PEN;
features->x_max =
get_unaligned_le16(&report[i + 3]);
i += 4;
} }
break; break;
case HID_USAGE_Y: case HID_USAGE_Y:
if (usage == WCM_DESKTOP) { if (finger) {
if (finger) { switch (features->type) {
switch (features->type) { case TABLETPC2FG:
case TABLETPC2FG: case MTSCREEN:
case MTSCREEN: case MTTPC:
case MTTPC:
features->y_max =
get_unaligned_le16(&report[i + 3]);
features->y_phy =
get_unaligned_le16(&report[i + 6]);
i += 7;
break;
case WACOM_24HDT:
features->y_max =
get_unaligned_le16(&report[i + 3]);
features->y_phy =
get_unaligned_le16(&report[i - 2]);
i += 7;
break;
case BAMBOO_PT:
features->y_phy =
get_unaligned_le16(&report[i + 3]);
features->y_max =
get_unaligned_le16(&report[i + 6]);
i += 12;
break;
default:
features->y_max =
features->x_max;
features->y_phy =
get_unaligned_le16(&report[i + 3]);
i += 4;
break;
}
} else if (pen) {
features->y_max = features->y_max =
get_unaligned_le16(&report[i + 3]); get_unaligned_le16(&report[i + 3]);
features->y_phy =
get_unaligned_le16(&report[i + 6]);
i += 7;
break;
case WACOM_24HDT:
features->y_max =
get_unaligned_le16(&report[i + 3]);
features->y_phy =
get_unaligned_le16(&report[i - 2]);
i += 7;
break;
case BAMBOO_PT:
features->y_phy =
get_unaligned_le16(&report[i + 3]);
features->y_max =
get_unaligned_le16(&report[i + 6]);
i += 12;
break;
default:
features->y_max =
features->x_max;
features->y_phy =
get_unaligned_le16(&report[i + 3]);
i += 4; i += 4;
break;
} }
} else if (pen) {
features->y_max =
get_unaligned_le16(&report[i + 3]);
i += 4;
} }
break; break;
@ -489,7 +470,7 @@ static int wacom_parse_hid(struct usb_interface *intf,
case HID_COLLECTION_END: case HID_COLLECTION_END:
/* reset UsagePage and Finger */ /* reset UsagePage and Finger */
finger = usage = 0; finger = page = 0;
break; break;
case HID_COLLECTION: case HID_COLLECTION: