diff options
Diffstat (limited to 'drivers/input/tablet')
| -rw-r--r-- | drivers/input/tablet/wacom_sys.c | 145 | ||||
| -rw-r--r-- | drivers/input/tablet/wacom_wac.c | 30 |
2 files changed, 130 insertions, 45 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; |
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 08b462b6c0d8..c3468c8dbd89 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c | |||
| @@ -25,6 +25,11 @@ | |||
| 25 | #define WACOM_INTUOS_RES 100 | 25 | #define WACOM_INTUOS_RES 100 |
| 26 | #define WACOM_INTUOS3_RES 200 | 26 | #define WACOM_INTUOS3_RES 200 |
| 27 | 27 | ||
| 28 | /* Scale factor relating reported contact size to logical contact area. | ||
| 29 | * 2^14/pi is a good approximation on Intuos5 and 3rd-gen Bamboo | ||
| 30 | */ | ||
| 31 | #define WACOM_CONTACT_AREA_SCALE 2607 | ||
| 32 | |||
| 28 | static int wacom_penpartner_irq(struct wacom_wac *wacom) | 33 | static int wacom_penpartner_irq(struct wacom_wac *wacom) |
| 29 | { | 34 | { |
| 30 | unsigned char *data = wacom->data; | 35 | unsigned char *data = wacom->data; |
| @@ -326,7 +331,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) | |||
| 326 | 331 | ||
| 327 | /* Enter report */ | 332 | /* Enter report */ |
| 328 | if ((data[1] & 0xfc) == 0xc0) { | 333 | if ((data[1] & 0xfc) == 0xc0) { |
| 329 | if (features->type >= INTUOS5S && features->type <= INTUOS5L) | 334 | if (features->quirks == WACOM_QUIRK_MULTI_INPUT) |
| 330 | wacom->shared->stylus_in_proximity = true; | 335 | wacom->shared->stylus_in_proximity = true; |
| 331 | 336 | ||
| 332 | /* serial number of the tool */ | 337 | /* serial number of the tool */ |
| @@ -414,7 +419,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) | |||
| 414 | 419 | ||
| 415 | /* Exit report */ | 420 | /* Exit report */ |
| 416 | if ((data[1] & 0xfe) == 0x80) { | 421 | if ((data[1] & 0xfe) == 0x80) { |
| 417 | if (features->type >= INTUOS5S && features->type <= INTUOS5L) | 422 | if (features->quirks == WACOM_QUIRK_MULTI_INPUT) |
| 418 | wacom->shared->stylus_in_proximity = false; | 423 | wacom->shared->stylus_in_proximity = false; |
| 419 | 424 | ||
| 420 | /* | 425 | /* |
| @@ -1043,11 +1048,19 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data) | |||
| 1043 | if (touch) { | 1048 | if (touch) { |
| 1044 | int x = (data[2] << 4) | (data[4] >> 4); | 1049 | int x = (data[2] << 4) | (data[4] >> 4); |
| 1045 | int y = (data[3] << 4) | (data[4] & 0x0f); | 1050 | int y = (data[3] << 4) | (data[4] & 0x0f); |
| 1046 | int w = data[6]; | 1051 | int a = data[5]; |
| 1052 | |||
| 1053 | // "a" is a scaled-down area which we assume is roughly | ||
| 1054 | // circular and which can be described as: a=(pi*r^2)/C. | ||
| 1055 | int x_res = input_abs_get_res(input, ABS_X); | ||
| 1056 | int y_res = input_abs_get_res(input, ABS_Y); | ||
| 1057 | int width = 2 * int_sqrt(a * WACOM_CONTACT_AREA_SCALE); | ||
| 1058 | int height = width * y_res / x_res; | ||
| 1047 | 1059 | ||
| 1048 | input_report_abs(input, ABS_MT_POSITION_X, x); | 1060 | input_report_abs(input, ABS_MT_POSITION_X, x); |
| 1049 | input_report_abs(input, ABS_MT_POSITION_Y, y); | 1061 | input_report_abs(input, ABS_MT_POSITION_Y, y); |
| 1050 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, w); | 1062 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, width); |
| 1063 | input_report_abs(input, ABS_MT_TOUCH_MINOR, height); | ||
| 1051 | } | 1064 | } |
| 1052 | } | 1065 | } |
| 1053 | 1066 | ||
| @@ -1533,7 +1546,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, | |||
| 1533 | input_mt_init_slots(input_dev, features->touch_max, 0); | 1546 | input_mt_init_slots(input_dev, features->touch_max, 0); |
| 1534 | 1547 | ||
| 1535 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, | 1548 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, |
| 1536 | 0, 255, 0, 0); | 1549 | 0, features->x_max, 0, 0); |
| 1550 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, | ||
| 1551 | 0, features->y_max, 0, 0); | ||
| 1537 | 1552 | ||
| 1538 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, | 1553 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, |
| 1539 | 0, features->x_max, | 1554 | 0, features->x_max, |
| @@ -1641,7 +1656,10 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, | |||
| 1641 | 1656 | ||
| 1642 | input_set_abs_params(input_dev, | 1657 | input_set_abs_params(input_dev, |
| 1643 | ABS_MT_TOUCH_MAJOR, | 1658 | ABS_MT_TOUCH_MAJOR, |
| 1644 | 0, 255, 0, 0); | 1659 | 0, features->x_max, 0, 0); |
| 1660 | input_set_abs_params(input_dev, | ||
| 1661 | ABS_MT_TOUCH_MINOR, | ||
| 1662 | 0, features->y_max, 0, 0); | ||
| 1645 | } | 1663 | } |
| 1646 | 1664 | ||
| 1647 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, | 1665 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, |
