diff options
| author | Jason Gerecke <killertofu@gmail.com> | 2014-04-19 16:46:40 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-04-19 16:57:34 -0400 |
| commit | 5866d9e3b7ecdf96a6089d12bb65736d7c473bce (patch) | |
| tree | 9f856291cb41ed1c3c852b676c2b1cfa84cb219b | |
| parent | 91ae0e77836b4a13f511b4fc62dc31c523858187 (diff) | |
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>
| -rw-r--r-- | drivers/input/tablet/wacom_sys.c | 237 |
1 files changed, 109 insertions, 128 deletions
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index b16ebef5b911..5be617755461 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c | |||
| @@ -22,23 +22,17 @@ | |||
| 22 | #define HID_USAGE_PAGE_DIGITIZER 0x0d | 22 | #define HID_USAGE_PAGE_DIGITIZER 0x0d |
| 23 | #define HID_USAGE_PAGE_DESKTOP 0x01 | 23 | #define HID_USAGE_PAGE_DESKTOP 0x01 |
| 24 | #define HID_USAGE 0x09 | 24 | #define HID_USAGE 0x09 |
| 25 | #define HID_USAGE_X 0x30 | 25 | #define HID_USAGE_X ((HID_USAGE_PAGE_DESKTOP << 16) | 0x30) |
| 26 | #define HID_USAGE_Y 0x31 | 26 | #define HID_USAGE_Y ((HID_USAGE_PAGE_DESKTOP << 16) | 0x31) |
| 27 | #define HID_USAGE_X_TILT 0x3d | 27 | #define HID_USAGE_X_TILT ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x3d) |
| 28 | #define HID_USAGE_Y_TILT 0x3e | 28 | #define HID_USAGE_Y_TILT ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x3e) |
| 29 | #define HID_USAGE_FINGER 0x22 | 29 | #define HID_USAGE_FINGER ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x22) |
| 30 | #define HID_USAGE_STYLUS 0x20 | 30 | #define HID_USAGE_STYLUS ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x20) |
| 31 | #define HID_USAGE_CONTACTMAX 0x55 | 31 | #define HID_USAGE_CONTACTMAX ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x55) |
| 32 | #define HID_COLLECTION 0xa1 | 32 | #define HID_COLLECTION 0xa1 |
| 33 | #define HID_COLLECTION_LOGICAL 0x02 | 33 | #define HID_COLLECTION_LOGICAL 0x02 |
| 34 | #define HID_COLLECTION_END 0xc0 | 34 | #define HID_COLLECTION_END 0xc0 |
| 35 | 35 | ||
| 36 | enum { | ||
| 37 | WCM_UNDEFINED = 0, | ||
| 38 | WCM_DESKTOP, | ||
| 39 | WCM_DIGITIZER, | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct hid_descriptor { | 36 | struct hid_descriptor { |
| 43 | struct usb_descriptor_header header; | 37 | struct usb_descriptor_header header; |
| 44 | __le16 bcdHID; | 38 | __le16 bcdHID; |
| @@ -305,7 +299,7 @@ static int wacom_parse_hid(struct usb_interface *intf, | |||
| 305 | char limit = 0; | 299 | char limit = 0; |
| 306 | /* result has to be defined as int for some devices */ | 300 | /* result has to be defined as int for some devices */ |
| 307 | int result = 0, touch_max = 0; | 301 | int result = 0, touch_max = 0; |
| 308 | int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0; | 302 | int i = 0, page = 0, finger = 0, pen = 0; |
| 309 | unsigned char *report; | 303 | unsigned char *report; |
| 310 | 304 | ||
| 311 | report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL); | 305 | report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL); |
| @@ -332,134 +326,121 @@ static int wacom_parse_hid(struct usb_interface *intf, | |||
| 332 | 326 | ||
| 333 | switch (report[i]) { | 327 | switch (report[i]) { |
| 334 | case HID_USAGE_PAGE: | 328 | case HID_USAGE_PAGE: |
| 335 | switch (report[i + 1]) { | 329 | page = report[i + 1]; |
| 336 | case HID_USAGE_PAGE_DIGITIZER: | 330 | i++; |
| 337 | usage = WCM_DIGITIZER; | ||
| 338 | i++; | ||
| 339 | break; | ||
| 340 | |||
| 341 | case HID_USAGE_PAGE_DESKTOP: | ||
| 342 | usage = WCM_DESKTOP; | ||
| 343 | i++; | ||
| 344 | break; | ||
| 345 | } | ||
| 346 | break; | 331 | break; |
| 347 | 332 | ||
| 348 | case HID_USAGE: | 333 | case HID_USAGE: |
| 349 | switch (report[i + 1]) { | 334 | switch (page << 16 | report[i + 1]) { |
| 350 | case HID_USAGE_X: | 335 | case HID_USAGE_X: |
| 351 | if (usage == WCM_DESKTOP) { | 336 | if (finger) { |
| 352 | if (finger) { | 337 | features->device_type = BTN_TOOL_FINGER; |
| 353 | features->device_type = BTN_TOOL_FINGER; | 338 | /* touch device at least supports one touch point */ |
| 354 | /* touch device at least supports one touch point */ | 339 | touch_max = 1; |
| 355 | touch_max = 1; | 340 | switch (features->type) { |
| 356 | switch (features->type) { | 341 | case TABLETPC2FG: |
| 357 | case TABLETPC2FG: | 342 | features->pktlen = WACOM_PKGLEN_TPC2FG; |
| 358 | features->pktlen = WACOM_PKGLEN_TPC2FG; | 343 | break; |
| 359 | break; | 344 | |
| 360 | 345 | case MTSCREEN: | |
| 361 | case MTSCREEN: | 346 | case WACOM_24HDT: |
| 362 | case WACOM_24HDT: | 347 | features->pktlen = WACOM_PKGLEN_MTOUCH; |
| 363 | features->pktlen = WACOM_PKGLEN_MTOUCH; | 348 | break; |
| 364 | break; | 349 | |
| 365 | 350 | case MTTPC: | |
| 366 | case MTTPC: | 351 | features->pktlen = WACOM_PKGLEN_MTTPC; |
| 367 | features->pktlen = WACOM_PKGLEN_MTTPC; | 352 | break; |
| 368 | break; | 353 | |
| 369 | 354 | case BAMBOO_PT: | |
| 370 | case BAMBOO_PT: | 355 | features->pktlen = WACOM_PKGLEN_BBTOUCH; |
| 371 | features->pktlen = WACOM_PKGLEN_BBTOUCH; | 356 | break; |
| 372 | break; | 357 | |
| 373 | 358 | default: | |
| 374 | default: | 359 | features->pktlen = WACOM_PKGLEN_GRAPHIRE; |
| 375 | features->pktlen = WACOM_PKGLEN_GRAPHIRE; | 360 | break; |
| 376 | break; | 361 | } |
| 377 | } | 362 | |
| 378 | 363 | switch (features->type) { | |
| 379 | switch (features->type) { | 364 | case BAMBOO_PT: |
| 380 | case BAMBOO_PT: | 365 | features->x_phy = |
| 381 | features->x_phy = | 366 | get_unaligned_le16(&report[i + 5]); |
| 382 | get_unaligned_le16(&report[i + 5]); | 367 | features->x_max = |
| 383 | features->x_max = | 368 | get_unaligned_le16(&report[i + 8]); |
| 384 | get_unaligned_le16(&report[i + 8]); | 369 | i += 15; |
| 385 | i += 15; | 370 | break; |
| 386 | break; | 371 | |
| 387 | 372 | case WACOM_24HDT: | |
| 388 | case WACOM_24HDT: | ||
| 389 | features->x_max = | ||
| 390 | get_unaligned_le16(&report[i + 3]); | ||
| 391 | features->x_phy = | ||
| 392 | get_unaligned_le16(&report[i + 8]); | ||
| 393 | features->unit = report[i - 1]; | ||
| 394 | features->unitExpo = report[i - 3]; | ||
| 395 | i += 12; | ||
| 396 | break; | ||
| 397 | |||
| 398 | default: | ||
| 399 | features->x_max = | ||
| 400 | get_unaligned_le16(&report[i + 3]); | ||
| 401 | features->x_phy = | ||
| 402 | get_unaligned_le16(&report[i + 6]); | ||
| 403 | features->unit = report[i + 9]; | ||
| 404 | features->unitExpo = report[i + 11]; | ||
| 405 | i += 12; | ||
| 406 | break; | ||
| 407 | } | ||
| 408 | } else if (pen) { | ||
| 409 | /* penabled only accepts exact bytes of data */ | ||
| 410 | if (features->type >= TABLETPC) | ||
| 411 | features->pktlen = WACOM_PKGLEN_GRAPHIRE; | ||
| 412 | features->device_type = BTN_TOOL_PEN; | ||
| 413 | features->x_max = | 373 | features->x_max = |
| 414 | get_unaligned_le16(&report[i + 3]); | 374 | get_unaligned_le16(&report[i + 3]); |
| 415 | i += 4; | 375 | features->x_phy = |
| 376 | get_unaligned_le16(&report[i + 8]); | ||
| 377 | features->unit = report[i - 1]; | ||
| 378 | features->unitExpo = report[i - 3]; | ||
| 379 | i += 12; | ||
| 380 | break; | ||
| 381 | |||
| 382 | default: | ||
| 383 | features->x_max = | ||
| 384 | get_unaligned_le16(&report[i + 3]); | ||
| 385 | features->x_phy = | ||
| 386 | get_unaligned_le16(&report[i + 6]); | ||
| 387 | features->unit = report[i + 9]; | ||
| 388 | features->unitExpo = report[i + 11]; | ||
| 389 | i += 12; | ||
| 390 | break; | ||
| 416 | } | 391 | } |
| 392 | } else if (pen) { | ||
| 393 | /* penabled only accepts exact bytes of data */ | ||
| 394 | if (features->type >= TABLETPC) | ||
| 395 | features->pktlen = WACOM_PKGLEN_GRAPHIRE; | ||
| 396 | features->device_type = BTN_TOOL_PEN; | ||
| 397 | features->x_max = | ||
| 398 | get_unaligned_le16(&report[i + 3]); | ||
| 399 | i += 4; | ||
| 417 | } | 400 | } |
| 418 | break; | 401 | break; |
| 419 | 402 | ||
| 420 | case HID_USAGE_Y: | 403 | case HID_USAGE_Y: |
| 421 | if (usage == WCM_DESKTOP) { | 404 | if (finger) { |
| 422 | if (finger) { | 405 | switch (features->type) { |
| 423 | switch (features->type) { | 406 | case TABLETPC2FG: |
| 424 | case TABLETPC2FG: | 407 | case MTSCREEN: |
| 425 | case MTSCREEN: | 408 | case MTTPC: |
| 426 | case MTTPC: | 409 | features->y_max = |
| 427 | features->y_max = | 410 | get_unaligned_le16(&report[i + 3]); |
| 428 | get_unaligned_le16(&report[i + 3]); | 411 | features->y_phy = |
| 429 | features->y_phy = | 412 | get_unaligned_le16(&report[i + 6]); |
| 430 | get_unaligned_le16(&report[i + 6]); | 413 | i += 7; |
| 431 | i += 7; | 414 | break; |
| 432 | break; | 415 | |
| 433 | 416 | case WACOM_24HDT: | |
| 434 | case WACOM_24HDT: | 417 | features->y_max = |
| 435 | features->y_max = | 418 | get_unaligned_le16(&report[i + 3]); |
| 436 | get_unaligned_le16(&report[i + 3]); | 419 | features->y_phy = |
| 437 | features->y_phy = | 420 | get_unaligned_le16(&report[i - 2]); |
| 438 | get_unaligned_le16(&report[i - 2]); | 421 | i += 7; |
| 439 | i += 7; | 422 | break; |
| 440 | break; | 423 | |
| 441 | 424 | case BAMBOO_PT: | |
| 442 | case BAMBOO_PT: | 425 | features->y_phy = |
| 443 | features->y_phy = | 426 | get_unaligned_le16(&report[i + 3]); |
| 444 | get_unaligned_le16(&report[i + 3]); | 427 | features->y_max = |
| 445 | features->y_max = | 428 | get_unaligned_le16(&report[i + 6]); |
| 446 | get_unaligned_le16(&report[i + 6]); | 429 | i += 12; |
| 447 | i += 12; | 430 | break; |
| 448 | break; | 431 | |
| 449 | 432 | default: | |
| 450 | default: | ||
| 451 | features->y_max = | ||
| 452 | features->x_max; | ||
| 453 | features->y_phy = | ||
| 454 | get_unaligned_le16(&report[i + 3]); | ||
| 455 | i += 4; | ||
| 456 | break; | ||
| 457 | } | ||
| 458 | } else if (pen) { | ||
| 459 | features->y_max = | 433 | features->y_max = |
| 434 | features->x_max; | ||
| 435 | features->y_phy = | ||
| 460 | get_unaligned_le16(&report[i + 3]); | 436 | get_unaligned_le16(&report[i + 3]); |
| 461 | i += 4; | 437 | i += 4; |
| 438 | break; | ||
| 462 | } | 439 | } |
| 440 | } else if (pen) { | ||
| 441 | features->y_max = | ||
| 442 | get_unaligned_le16(&report[i + 3]); | ||
| 443 | i += 4; | ||
| 463 | } | 444 | } |
| 464 | break; | 445 | break; |
| 465 | 446 | ||
| @@ -489,7 +470,7 @@ static int wacom_parse_hid(struct usb_interface *intf, | |||
| 489 | 470 | ||
| 490 | case HID_COLLECTION_END: | 471 | case HID_COLLECTION_END: |
| 491 | /* reset UsagePage and Finger */ | 472 | /* reset UsagePage and Finger */ |
| 492 | finger = usage = 0; | 473 | finger = page = 0; |
| 493 | break; | 474 | break; |
| 494 | 475 | ||
| 495 | case HID_COLLECTION: | 476 | case HID_COLLECTION: |
