diff options
Diffstat (limited to 'drivers/input/tablet/wacom_sys.c')
| -rw-r--r-- | drivers/input/tablet/wacom_sys.c | 145 |
1 files changed, 106 insertions, 39 deletions
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 0d3219f29744..9edf9806cff9 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c | |||
| @@ -172,6 +172,76 @@ static void wacom_close(struct input_dev *dev) | |||
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | /* | 174 | /* |
| 175 | * Calculate the resolution of the X or Y axis, given appropriate HID data. | ||
| 176 | * This function is little more than hidinput_calc_abs_res stripped down. | ||
| 177 | */ | ||
| 178 | static int wacom_calc_hid_res(int logical_extents, int physical_extents, | ||
| 179 | unsigned char unit, unsigned char exponent) | ||
| 180 | { | ||
| 181 | int prev, unit_exponent; | ||
| 182 | |||
| 183 | /* Check if the extents are sane */ | ||
| 184 | if (logical_extents <= 0 || physical_extents <= 0) | ||
| 185 | return 0; | ||
| 186 | |||
| 187 | /* Get signed value of nybble-sized twos-compliment exponent */ | ||
| 188 | unit_exponent = exponent; | ||
| 189 | if (unit_exponent > 7) | ||
| 190 | unit_exponent -= 16; | ||
| 191 | |||
| 192 | /* Convert physical_extents to millimeters */ | ||
| 193 | if (unit == 0x11) { /* If centimeters */ | ||
| 194 | unit_exponent += 1; | ||
| 195 | } else if (unit == 0x13) { /* If inches */ | ||
| 196 | prev = physical_extents; | ||
| 197 | physical_extents *= 254; | ||
| 198 | if (physical_extents < prev) | ||
| 199 | return 0; | ||
| 200 | unit_exponent -= 1; | ||
| 201 | } else { | ||
| 202 | return 0; | ||
| 203 | } | ||
| 204 | |||
| 205 | /* Apply negative unit exponent */ | ||
| 206 | for (; unit_exponent < 0; unit_exponent++) { | ||
| 207 | prev = logical_extents; | ||
| 208 | logical_extents *= 10; | ||
| 209 | if (logical_extents < prev) | ||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | /* Apply positive unit exponent */ | ||
| 213 | for (; unit_exponent > 0; unit_exponent--) { | ||
| 214 | prev = physical_extents; | ||
| 215 | physical_extents *= 10; | ||
| 216 | if (physical_extents < prev) | ||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | /* Calculate resolution */ | ||
| 221 | return logical_extents / physical_extents; | ||
| 222 | } | ||
| 223 | |||
| 224 | /* | ||
| 225 | * The physical dimension specified by the HID descriptor is likely not in | ||
| 226 | * the "100th of a mm" units expected by wacom_calculate_touch_res. This | ||
| 227 | * function adjusts the value of [xy]_phy based on the unit and exponent | ||
| 228 | * provided by the HID descriptor. If an error occurs durring conversion | ||
| 229 | * (e.g. from the unit being left unspecified) [xy]_phy is not modified. | ||
| 230 | */ | ||
| 231 | static void wacom_fix_phy_from_hid(struct wacom_features *features) | ||
| 232 | { | ||
| 233 | int xres = wacom_calc_hid_res(features->x_max, features->x_phy, | ||
| 234 | features->unit, features->unitExpo); | ||
| 235 | int yres = wacom_calc_hid_res(features->y_max, features->y_phy, | ||
| 236 | features->unit, features->unitExpo); | ||
| 237 | |||
| 238 | if (xres > 0 && yres > 0) { | ||
| 239 | features->x_phy = (100 * features->x_max) / xres; | ||
| 240 | features->y_phy = (100 * features->y_max) / yres; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | /* | ||
| 175 | * Static values for max X/Y and resolution of Pen interface is stored in | 245 | * Static values for max X/Y and resolution of Pen interface is stored in |
| 176 | * features. This mean physical size of active area can be computed. | 246 | * features. This mean physical size of active area can be computed. |
| 177 | * This is useful to do when Pen and Touch have same active area of tablet. | 247 | * This is useful to do when Pen and Touch have same active area of tablet. |
| @@ -432,56 +502,52 @@ static int wacom_parse_hid(struct usb_interface *intf, | |||
| 432 | return result; | 502 | return result; |
| 433 | } | 503 | } |
| 434 | 504 | ||
| 435 | static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features) | 505 | static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int length, int mode) |
| 436 | { | 506 | { |
| 437 | unsigned char *rep_data; | 507 | unsigned char *rep_data; |
| 438 | int limit = 0, report_id = 2; | 508 | int error = -ENOMEM, limit = 0; |
| 439 | int error = -ENOMEM; | ||
| 440 | 509 | ||
| 441 | rep_data = kmalloc(4, GFP_KERNEL); | 510 | rep_data = kzalloc(length, GFP_KERNEL); |
| 442 | if (!rep_data) | 511 | if (!rep_data) |
| 443 | return error; | 512 | return error; |
| 444 | 513 | ||
| 445 | /* ask to report Wacom data */ | 514 | rep_data[0] = report_id; |
| 515 | rep_data[1] = mode; | ||
| 516 | |||
| 517 | do { | ||
| 518 | error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, | ||
| 519 | report_id, rep_data, length, 1); | ||
| 520 | if (error >= 0) | ||
| 521 | error = wacom_get_report(intf, WAC_HID_FEATURE_REPORT, | ||
| 522 | report_id, rep_data, length, 1); | ||
| 523 | } while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES); | ||
| 524 | |||
| 525 | kfree(rep_data); | ||
| 526 | |||
| 527 | return error < 0 ? error : 0; | ||
| 528 | } | ||
| 529 | |||
| 530 | /* | ||
| 531 | * Switch the tablet into its most-capable mode. Wacom tablets are | ||
| 532 | * typically configured to power-up in a mode which sends mouse-like | ||
| 533 | * reports to the OS. To get absolute position, pressure data, etc. | ||
| 534 | * from the tablet, it is necessary to switch the tablet out of this | ||
| 535 | * mode and into one which sends the full range of tablet data. | ||
| 536 | */ | ||
| 537 | static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features) | ||
| 538 | { | ||
| 446 | if (features->device_type == BTN_TOOL_FINGER) { | 539 | if (features->device_type == BTN_TOOL_FINGER) { |
| 447 | /* if it is an MT Tablet PC touch */ | ||
| 448 | if (features->type > TABLETPC) { | 540 | if (features->type > TABLETPC) { |
| 449 | do { | 541 | /* MT Tablet PC touch */ |
| 450 | rep_data[0] = 3; | 542 | return wacom_set_device_mode(intf, 3, 4, 4); |
| 451 | rep_data[1] = 4; | 543 | } |
| 452 | rep_data[2] = 0; | 544 | } else if (features->device_type == BTN_TOOL_PEN) { |
| 453 | rep_data[3] = 0; | 545 | if (features->type <= BAMBOO_PT && features->type != WIRELESS) { |
| 454 | report_id = 3; | 546 | return wacom_set_device_mode(intf, 2, 2, 2); |
| 455 | error = wacom_set_report(intf, | ||
| 456 | WAC_HID_FEATURE_REPORT, | ||
| 457 | report_id, | ||
| 458 | rep_data, 4, 1); | ||
| 459 | if (error >= 0) | ||
| 460 | error = wacom_get_report(intf, | ||
| 461 | WAC_HID_FEATURE_REPORT, | ||
| 462 | report_id, | ||
| 463 | rep_data, 4, 1); | ||
| 464 | } while ((error < 0 || rep_data[1] != 4) && | ||
| 465 | limit++ < WAC_MSG_RETRIES); | ||
| 466 | } | 547 | } |
| 467 | } else if (features->type <= BAMBOO_PT && | ||
| 468 | features->type != WIRELESS && | ||
| 469 | features->device_type == BTN_TOOL_PEN) { | ||
| 470 | do { | ||
| 471 | rep_data[0] = 2; | ||
| 472 | rep_data[1] = 2; | ||
| 473 | error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, | ||
| 474 | report_id, rep_data, 2, 1); | ||
| 475 | if (error >= 0) | ||
| 476 | error = wacom_get_report(intf, | ||
| 477 | WAC_HID_FEATURE_REPORT, | ||
| 478 | report_id, rep_data, 2, 1); | ||
| 479 | } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES); | ||
| 480 | } | 548 | } |
| 481 | 549 | ||
| 482 | kfree(rep_data); | 550 | return 0; |
| 483 | |||
| 484 | return error < 0 ? error : 0; | ||
| 485 | } | 551 | } |
| 486 | 552 | ||
| 487 | static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, | 553 | static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, |
| @@ -531,6 +597,7 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, | |||
| 531 | error = wacom_parse_hid(intf, hid_desc, features); | 597 | error = wacom_parse_hid(intf, hid_desc, features); |
| 532 | if (error) | 598 | if (error) |
| 533 | goto out; | 599 | goto out; |
| 600 | wacom_fix_phy_from_hid(features); | ||
| 534 | 601 | ||
| 535 | out: | 602 | out: |
| 536 | return error; | 603 | return error; |
