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 /drivers/input | |
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>
Diffstat (limited to 'drivers/input')
-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: |